11

I'm using TabLayout and viewPager with an option to swipe the viewPager to the left or right in order to navigate between pages.

My problem is, that my application is RTL based (right-to-left) and the swipe direction is reversed.

I'm trying to change the swipe direction from the default to the reversed version. I've been searching alot on the web and couldn't find a way how to do it.

I'm using android.support.v4.view.ViewPager;

and this is how I initialize my TabLayout with the viewPager:

// View Page Adapter
        final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
        final PagerAdapter adapter = new PagerAdapter
                (getSupportFragmentManager(), tabLayout.getTabCount());
        //View Page Adapter Configuration
        viewPager.setAdapter(adapter);
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
        viewPager.setOffscreenPageLimit(3);
        tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                viewPager.setCurrentItem(tab.getPosition());
            }

Summary: Currently, When I'm swiping the viewPager to the left, it shows the next page. in RTL, when you swipe the viewPager to the right, it shows the next page.

It might be hard to understand, but here it is. Swiping right shows the next page

Swiping right shows the next page

while I need swiping right to show the previous page.

Eliran
  • 207
  • 1
  • 2
  • 11
  • Isn't this just a matter of having the contents of the `PagerAdapter` in the reverse order? – CommonsWare Sep 07 '15 at 17:30
  • 2
    Why not just setCurrentItem to the last item? – Chris Sep 07 '15 at 17:30
  • @CommonsWare And what happens when I swipe left? Don't I need to change the onScrollListener for this? (same answer to you Chris) I need to change the viewPager scrolling direction (swiping right - next page, swiping left - previous page). now it's reversed. The tabs are working great if I select one. the viewPager swiping does not. – Eliran Sep 07 '15 at 17:33
  • "And what happens when I swipe left?" -- whatever normally happens when you swipe left. Based on your edit, reversing the contents of the `PagerAdapter` would seem to be what you want. There really is no concept of "next page" or "previous page" in `ViewPager`, as it only cares about page index values. It is up to you to order the contents of your `PagerAdapter` such that "next page" means what you want it to. This may also mean that you need to set the starting page index at the end, per Chris' comment, depending on what you want your starting state to be. – CommonsWare Sep 07 '15 at 17:38
  • @CommonsWare I think you misunderstand my question, or I didnt explained what I need good. I edited my comment-answer to you with new information, I hope you understand. – Eliran Sep 07 '15 at 17:39
  • `ViewPager` does not have "next". `ViewPager` does not have "previous". Those are your terms, that you are layering on top of what the `ViewPager` API offers. Until you decide what "next" and "previous" means **in terms of the `ViewPager` API** and its page index values, nobody can really help you. How *I* would translate "next" and "previous" to in terms of the `ViewPager` API lines up with what I suggested in my earlier comments. – CommonsWare Sep 07 '15 at 17:47
  • Well I've been thinking and It can work, but then I'll end up with the 3rd tab acts as the first one, and the first tab acts like the 3rd one. In addition, in my tab layout the "last" tab will be selected by default.. – Eliran Sep 07 '15 at 18:16
  • @Chris and the last item will be highlighted in the TabLayout, instead of the firts one.. – Eliran Sep 10 '15 at 13:35
  • @CommonsWare Solution of this question doesn't work for Api level 28. Can you please check : https://stackoverflow.com/q/54129324/3484668 – Rushi M Thakker Jan 11 '19 at 07:20

6 Answers6

29

It is the very simple techniqe to change the swipe direction of the Viewpager.

There are two simple step which have to follow you,

1. Change the rotation of the View pager,

viewpager.setRotationY(180);

2. Then again change the direction of the each item view in adapter,

itemView.setRotationY(180);

This is 100% worked for me.

Aman Gupta - ΔMΔN
  • 2,971
  • 2
  • 19
  • 39
  • 3
    this reverse all views inside the viewpager –  Feb 07 '17 at 17:32
  • 2
    Because maybe you have rotated your layout only once. You have to rotate twice. Once parent layout than the child layout. Definitely, It will work properly. – Aman Gupta - ΔMΔN Jul 05 '17 at 06:23
  • Any idea how to rotate the text in PagerTitleStrip back to normal got expected behavior when rotating views twice ....but pager title strip when rotate 180 switches parent view direction of just Title Strip but not the text – skryshtafovych Aug 29 '17 at 22:56
  • this solution works fine but on some of Huawei devices this will cause white screen but recycler view items is still clickable but invisible Idk why but it happens to me and when I remove setRotationY Its works – Biro Nader Aug 10 '18 at 03:21
  • This solution is having issues with Android P devices. – Rushi M Thakker Jan 11 '19 at 07:15
  • @AmanGupta-ShOoTeR any workaround for pie. https://stackoverflow.com/q/54129324/3484668 – Rushi M Thakker Jan 11 '19 at 07:23
  • @RushiMThakker you can check the new answer: https://stackoverflow.com/a/54440185/5333711 – Aman Gupta - ΔMΔN Jan 30 '19 at 12:02
13

I faced the same problem month ago but I think I found a great solution.

  1. Change your TabLayout direction to ltr in xml:
     <android.support.design.widget.TabLayout
        android:id="@+id/tl_activity_main"
        android:layout_below="@id/toolbar_activity_main"
        android:layoutDirection="ltr"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@style/DisionTabLayout" />
  1. Create custom adapter for ViewPager and override methods getItem(int position) and getPageTitle(int position):
    @Override
    public Fragment getItem(int position) {
        if (mIsRtlOrientation && mTabs != null && mTabs.length > 0) {
            return mTabs[mTabs.length - position - 1].getFragment();
        } else {
            return mTabs[position].getFragment();
        }
    }

    @Override
    public int getCount() {
        return mTabs.length;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        if (mIsRtlOrientation && mTabs != null && mTabs.length > 0) {
            return mTabs[mTabs.length - position - 1].getTitle();
        } else {
            return mTabs[position].getTitle();
        }
    }
  1. Set the adapter to ViewPager and then apply this ViewPager to TabLayout.
    private void setAdapters() {
        // initialize adapter
        mTabsAdapter = new TabsAdapter(getSupportFragmentManager(), mTabs, true);
        // set adapter to ViewPager
        vp.setAdapter(mTabsAdapter);
        // set ViewPager to TabLayout
        tl.setupWithViewPager(vp);
        // if RTL orientation, go to last item
        vp.setCurrentItem(vp.getAdapter().getCount() - 1, false);
    }
Stefan Tsekov
  • 161
  • 1
  • 8
0

i know it's late but this is a smart question. as @CommonsWare said it's the matter of reversing the order of items in getItem() method in page adapter. but this isn't enought. as you reverse the order in getitem() method you should also NOT reverse the order in getPageTitle() method. something like this:

public static class AppSectionsPagerAdapter extends FragmentStatePagerAdapter {
        public AppSectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            switch (position) {
                case 0:
                    return new page1();
                case 1:
                    return new page2();
                case 2:
                    return new page3();
            }
        }

        @Override
        public CharSequence getPageTitle(int position) {
            switch (position) {
                case 0:
                    return "page 3 title";
                case 1:
                    return "page 2 title";
                case 2:
                    return "page 1 title";
                }
        }

        @Override
        public int getCount() {
            return 3;
        }
    }

now comes the tricky part. you should use this simple method which converts zero based index order reversed using max index and current index.

public int calculateReverse(int maxIndex,int currentIndex){
        return maxIndex-currentIndex;
    }

than you should use this method in onTabSelected() like this: be aware you should use your own max index:

@Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
        mViewPager.setCurrentItem(calculateReverse(2,tab.getPosition()));
    }

the second part is to change page listener on page adapter. once again you should use your own max index number:

mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                actionBar.setSelectedNavigationItem(calculateReverse(2,position));  // reversing the tab selection
            }
        });

i tried to be as descriptive as i can. hope this helps :)

hadi
  • 1,104
  • 8
  • 23
0

If you are using viewpager2 with fragments. you can use.

<androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager"
        android:layout_width="0dp"
        android:layout_height="0dp"
        **android:orientation="vertical"**
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

I hope this helps somebody.

David Innocent
  • 606
  • 5
  • 16
0

You can use ViewPager2, It support right to left direction. to make it possible:

  1. Add android:supportsRtl="true" in app Manifest
  2. Make viewpager2's parent viewgroup layout direction ltr (android:layoutDirection="ltr")
  3. Now set viewpager2's layoutDirection ltr (android:layoutDirection="rtl")
  4. also set adapter's layout to layoutDirection ltr (android:layoutDirection="ltr")
Abu Nayem
  • 101
  • 3
  • 11
0

So I found that the easiest way for this to work for ViewPager (1) is just to invert the array of items, and then before displaying set the current item of the pager at [array size] position.

Sava Gavran
  • 41
  • 1
  • 4