How to create RTL ViewPager?

After a long research I found a very simple solution. Without reverse adapters, rotation child in their classes and etc.

open class RtlViewPager : ViewPager {

    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    override fun onRtlPropertiesChanged(layoutDirection: Int) {
        super.onRtlPropertiesChanged(layoutDirection)
        if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
            rotationY = 180f
        }
    }

    override fun onViewAdded(child: View?) {
        if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
            child?.rotationY = 180f
        }
        super.onViewAdded(child)
    }

}

Rewrite with Java :

public class RtlViewPager extends ViewPager {
    public RtlViewPager(@NonNull Context context) {
        super(context);
    }

    public RtlViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void onRtlPropertiesChanged(int layoutDirection) {
        super.onRtlPropertiesChanged(layoutDirection);
        if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
            setRotationY(180f);
        }
    }

    @Override
    public void onViewAdded(View child) {
        if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
            child.setRotationY(180);
        }
        super.onViewAdded(child);
    }
}

this library RtlViewPager Does the job cleanly

only requires replacing

<android.support.v4.view.ViewPager

with

<com.duolingo.open:rtl-viewpager

in the XML

it also supports tabLayout

using this approach is cleaner since it doesn't require reversing the Adapter logic

Also see this issue report for google


After a lot of research I realized how to do it. What I needed to do is to reverse the order of the fragments (when initialize them to the ViewPager) and do viewPager.setCurrentItem(ViewPagerSize). But it's has to happen only if the locale is RTL so I used a method to determine if it is.

This is the code:

 public static boolean isRTL() {
    return isRTL(Locale.getDefault());
 }

 public static boolean isRTL(Locale locale) {
    final int directionality = Character.getDirectionality(locale.getDisplayName().charAt(0));
    return directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
            directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC;
 }

private void setupViewPager(ViewPager viewPager) {
    ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
    if (isRTL()) {
        // The view has RTL layout
        adapter.addFragment(new S7(), getString(R.string.stage7));
        adapter.addFragment(new S6(), getString(R.string.stage6));
        adapter.addFragment(new S5(), getString(R.string.stage5));
        adapter.addFragment(new S4(), getString(R.string.stage4));
        adapter.addFragment(new S3(), getString(R.string.stage3));
        adapter.addFragment(new S2(), getString(R.string.stage2));
        adapter.addFragment(new S1(), getString(R.string.stage1));
        adapter.addFragment(new Intro(), getString(R.string.Introduction));
    } else {
        // The view has LTR layout
        adapter.addFragment(new Intro(), getString(R.string.Introduction));
        adapter.addFragment(new S1(), getString(R.string.stage1));
        adapter.addFragment(new S2(), getString(R.string.stage2));
        adapter.addFragment(new S3(), getString(R.string.stage3));
        adapter.addFragment(new S4(), getString(R.string.stage4));
        adapter.addFragment(new S5(), getString(R.string.stage5));
        adapter.addFragment(new S6(), getString(R.string.stage6));
        adapter.addFragment(new S7(), getString(R.string.stage7));
    }
    viewPager.setAdapter(adapter);
}

And for the tabs I had to set the direction to LTR (It's looks messy when it's RTL).

So I used this code (It's only available in API 17+):

 TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        tabLayout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
    }

I could'nt find a way to do this on pre API 17.


My solution is adding android:rotationY="@integer/view_pager_rotation" attribute to viewPager in xml.

values/integers contains <integer name="view_pager_rotation">0</integer>

values-ldrtl/integers contains <integer name="view_pager_rotation">180</integer>

Note that the content is also get rotated.

Update 02/11/2019

Now it's supported with viewpager2 .