How to make vertical PagerTabStrip for VerticalViewPager android - android

I have a custom vertical view pager that extends view pager. now i want to include pagerTabStrip. Now the thing is it can be align either on top or bottom. But for this customized viewpager i need vertical pagertabstrip as the pages/fragments scrolls verticall.
Here is the code of VerticalViewPager
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
}
The Xml for the VewPager is
<com.mypackage.customViews.VerticalViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp"
android:scrollIndicators="top"
>
<android.support.v4.view.PagerTabStrip
android:id="#+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
layout_gravity="right"
android:paddingBottom="#dimen/padding8"
android:paddingTop="#dimen/padding8"
android:textColor="#color/link_color" />
</com.TCYonline.android.BetterThink.customViews.VerticalViewPager>
Please help me out.

Related

Vertical ViewPager with smooth scrolling and page transformation like inshorts app

I wanted to make a Vertical ViewPager looklike inshorts application.
I have tried several solutions found on Stack Overflow and in Github.
All of them have the same way of implementation of code, and all of them have the same lagging issue while scrolling up and down(vertical scroll), you can see in the video, but the design implementation is same as inshorts.
The link which I have tried are,
1) VerticalViewPager
2) DirectionViewPager
3) Github Repos
I have also tried for mFlingDistance,mMinimumVelocity etc from android's Viewpager class for increasing fling in Viewpager. But with no luck of making it working.
Below is my VerticalViewPager class
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
}
And using VerticaPageTransformer class for page transition.
class VerticalPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
#Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // [0,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
The one that worked for me was of castorflex solution for smooth scrolling, but when I apply a PageTransformer to castorflex solution, instead of scrolling vertically is scroll diagonally.You can see the reference video here.
I have also tried with ViewPager2 and with RecyclerView(with SnapHelper) but with viewpager2, I am getting the same diagonal issue. And with Snaphelper, I am unable to provide a page effect like inshorts(see the videos). May be, it will be possible by LinearLayoutManager of RecyclerView, as I have seen here. But failed to convert my page animation.
So anyone can give me any hint, or any idea about
1) How to make smooth scrolling with above approach? or
2) How to make vertical page transition from below approach, instead of diagonal? or
3) Or any other way if you people have.
Thanks in advance
You can see Castorflex's VerticalViewPager class, and using the same VerticlePageTransform class for page transformation
Check this Github Repo https://github.com/dipanshukr/Viewpager-Transformation
SampleActivity.java
private void initViewPager() {
VerticalViewPager viewPager = (VerticalViewPager) findViewById(R.id.vertical_viewpager);
//viewPager.setPageTransformer(false, new ZoomOutTransformer());
//viewPager.setPageTransformer(true, new StackTransformer());
String title = "ContentFragment";
viewPager.setAdapter(new ContentFragmentAdapter.Holder(getSupportFragmentManager())
.add(ContentFragment.newInstance(title, 1))
.add(ContentFragment.newInstance(title, 2))
.add(ContentFragment.newInstance(title, 3))
.add(ContentFragment.newInstance(title, 4))
.add(ContentFragment.newInstance(title, 5))
.set());
// If you setting other scroll mode,
// the scrolled fade is shown from either side of display.
viewPager.setOverScrollMode(View.OVER_SCROLL_NEVER);
}
VerticalViewPager.java
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
this(context, null);
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
setPageTransformer(false, new DefaultTransformer());
}
private MotionEvent swapTouchEvent(MotionEvent event) {
float width = getWidth();
float height = getHeight();
float swappedX = (event.getY() / height) * width;
float swappedY = (event.getX() / width) * height;
event.setLocation(swappedX, swappedY);
return event;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercept = super.onInterceptTouchEvent(swapTouchEvent(event));
//If not intercept, touch event should not be swapped.
swapTouchEvent(event);
return intercept;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapTouchEvent(ev));
}
}
DefaultTransformer.java
public class DefaultTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
float alpha = 0;
if (0 <= position && position <= 1) {
alpha = 1 - position;
} else if (-1 < position && position < 0) {
alpha = position + 1;
}
view.setAlpha(alpha);
view.setTranslationX(view.getWidth() * -position);
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
}
}

Viewpager inside Viewpager Scroll Issue

in my main activity i have a horizontal viewpager. Inside one of the fragment of the viewpager i have another vertical viewpager. Both works fine. But for the horizontal viewpager, i need to scroll from the edge of the screens. But i want it to be scrolled from anywhere in the screen.
my horizontal viewpager setup:
viewPager = (ViewPager) findViewById(R.id.viewpager);
adapterViewPager = new HorizontalViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapterViewPager);
viewPager.setCurrentItem(1);
horizontal viewpager adapter:
public class HorizontalViewPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
public HorizontalViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return MoreFragment.newInstance("Fragment MoreFragment", "HA HA HA");
case 1:
return NewsFragment.newInstance("Fragment 1", "HA HA HA");
case 2:
return WebViewFragment.newInstance("Fragment Webview", "HA HA HA");
default:
return null;
}
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public CharSequence getPageTitle(int position) {
return "Tab " + position;
}
}
in my news fragment i have another viewpager.
viewPager = view.findViewById(R.id.shortpager);
adapterViewPager = new VerticalPagerAdapter(getActivity().getSupportFragmentManager(), newsList);
viewPager.setAdapter(adapterViewPager);
My vertical viewpager class:
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
#Override
public void transformPage(View view, float position) {
if (position <= -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left/top page
view.setAlpha(1);
ViewCompat.setElevation(view, 1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
view.setTranslationY(0);
//set Y position to swipe in from top
float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else if (position <= 1) { // [0,1]
view.setAlpha(1);
ViewCompat.setElevation(view, 2);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
view.setTranslationY(position * view.getHeight());
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(1);
view.setScaleY(1);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
}
vertical viewpager adapter:
public class VerticalPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
private final ArrayList<News> newsList;
public VerticalPagerAdapter(FragmentManager fm, ArrayList<News> newsList) {
super(fm);
this.newsList = newsList;
}
#Override
public Fragment getItem(int position) {
return ShortFragment.newInstance("Fragment 1", "HA HA HA", newsList.get(position));
}
#Override
public int getCount() {
return this.newsList.size();
}
#Override
public CharSequence getPageTitle(int position) {
return "Tab " + position;
}
}
Vertical viewpager scrolls smoothly. Currently for horizontal viewpager, i have to scroll from the edge of the screens. But i need to make it scrolled like the vertical one from anywhere in the screen.
Issue with your code is your VerticalViewPager
If you notice the code,
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
Step-1, Call super with swapped gesture.
Step-2, Perform actions on vertical view pager with current gesture.
And if you specifically see the comment, // return touch coordinates to original reference frame for any child views this clearly tells that gesture is first consumed by child.
So in your vertical view pager since you are swapping the gestures, it is consuming the Horizontal Gesture even before passing it to the parent. Thats why your horizontal view pager do not get the gesture.
If you are using Vertical View Pager with any conflicting gesture implementation like ScrollView, Lists, RecyclerView, ViewPager, etc. use the one as in the link below. It is deprecated but works with all Gesture Conflicting Views.
https://github.com/kaelaela/VerticalViewPager
I had this issue and I resolved it by wrapping the viewpager in a Scrollview
<ScrollView
android:id="#+id/nested_scroll"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/view_pager"
android:nestedScrollingEnabled="false"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>

Implement horizontal and vertical viewpager (Android)

I need to implement a viewpager that can do both horizontal and vertical paging. If the user switches the page vertically, a vertical PageTransformer should carry out the animation. Otherwise, the regular animation should happen.
I found a couple of libraries that attempt to solve this problem, but they run into problems when one of the views has a ScrollView inside.
If it's possible, I would like to implement it without third party libaries.
So far, all I have is the code for a vertical viewpager, but I can't figure out how to add the horizontal functionality as well:
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
}
Just for reference, this is the my vertical PageTransformer:
public class VerticalPageTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
Any help would be appreciated

Android: Scrollview vertical inside VerticalViewPager doesn't work properly

This is my VerticalViewPager:
public class VerticalViewPager extends ViewPager {
public interface OnTouchListener {
void onTouchDown();
void onTouchUp();
void onTouchMove();
}
private OnTouchListener mListener;
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
public void setOnTouchListener(OnTouchListener listener) {
mListener = listener;
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y setNum to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction() & MotionEventCompat.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mListener.onTouchDown();
break;
case MotionEvent.ACTION_UP:
mListener.onTouchUp();
break;
case MotionEvent.ACTION_MOVE:
mListener.onTouchMove();
break;
}
return super.onTouchEvent(swapXY(ev));
}
}
I put some fragments in this ViewPager. In the last fragment there is a ScrollView:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
...
<ScrollView
android:id="#+id/vertical_scrollview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="#dimen/keyline_4">
....
</LinearLayout>
</ScrollView>
</LinearLayout>
</RelativeLayout>
In this last fragment I can scroll in this page normally. But if I want to slide to the previous page in the VerticalViewPager, I can't, nothing happens.
Thanks by advance guys!
Try using a NestedScrollView instead of the ScrollView.

ViewPager makes camera preview white out

So here's the deal:
I have a custom ViewPager with a Camera Preview fragment and another page, both work fine on their own. The transition between the two makes the camera turn white instead of just maintaining the view. I used a modification to make it a Vertical view pager instead of horizontal.
Before it was vertical, the stock view pager worked just fine. Here's what it looked like before: http://i.imgur.com/eaaHGvR.gif
And now:
http://i.imgur.com/RKxiYZL.gif
What did I miss that's making it go white?
Custom View Pager:
public class VerticalPager extends ViewPager {
public VerticalPager(Context context) {
super(context);
init();
}
public VerticalPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
//view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
//view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
//view.setAlpha(0);
}
}
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
}
EDIT:
After some tinkering, I got closer, but still crazy amounts of flickering and bugs. Previously, on the horizontal, it had some edge-issues but did not flicker like this:
http://i.imgur.com/aBcreT9.gif
I added view.BringToFront(); in the verticalpager, and also requested transparency when I set the adapter on the pager itself.

Categories

Resources