TabLayout remove unnecessary scrolling
Asked Answered
T

7

10

I've encountered the tricky problem with android TabLayout

import android.support.design.widget.TabLayout;

To see what's going on, look at this gif

When I select the foremost tab to the left, then scroll tabs to the right and select the foremost tab to the right, TabLayout first shows me the left tab again and then scrolls to selected tab to the right. Here's my setup code

    void setupTabs(ViewPager viewPager, TabLayout tabLayout) {
       ProductsPagerAdapter adapter = new ProductsPagerAdapter(getChildFragmentManager(), rootCategory.getChildCategories());
       viewPager.setAdapter(adapter);
       tabLayout.setupWithViewPager(viewPager);

       setStartingSelection(viewPager, adapter);


   }

    private void setStartingSelection(ViewPager viewPager, ProductsPagerAdapter adapter) {
        for(int i = 0 ; i < adapter.getCount(); i++){
            String title = (String) adapter.getPageTitle(i);
            if(title.equals(selectedCategory.getName())){
                viewPager.setCurrentItem(i);
                break;
            }
        }
    }

And layout

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/toolbar_color"
            app:navigationIcon="@drawable/ic_back_white"
            app:title="@string/title_transport"
            app:titleTextColor="@color/title_color"/>


        <android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabMode="scrollable"
            app:tabTextColor="@color/white"
            app:tabIndicatorColor="@color/tab_indicator"
            app:tabGravity="fill"/>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1"
        android:background="@android:color/white" />

</LinearLayout>
Teplica answered 27/1, 2017 at 10:17 Comment(4)
AppBarLayout should be a direct child of CoordinatorLayout though! developer.android.com/reference/android/support/design/widget/…Sites
I tried to change it, but it doesn't change anythingTeplica
If you comment in call of setStartingSelection method in setupTabs, does problem still persists?Tupungato
Yes, setting starting section has nothing to do with how this widget scrolls when you select itemTeplica
T
0

After a lot of search I understood that I need another component which will look like TabLayout, but won't be TabLayout. So I used ViewPagerIndicator.

It is very similar to TabLayout, though it lacks cool selection animations and selected tab indicator animations, which are present in TabLayout. It also doesn't resize text to fit tabs, which is good, and it doesn't resize tabs to fit text either, which is bad (tried all style parameters that I know - could not make it wrap the text).

But it selects tabs just fine and without additional scrolling. AndroidArsenal unfortunately does not contain solutions, which are better than that (at least it didn't when I searched).

Teplica answered 3/2, 2017 at 12:26 Comment(0)
I
5

you can try this code

    tabLayout.setupWithViewPager(viewPager);
    // little hack to prevent unnecessary tab scrolling
    tabLayout.clearOnTabSelectedListeners();
    tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            viewPager.setCurrentItem(tab.getPosition(), false);
        }

        @Override
        public void onTabUnselected(TabLayout.Tab tab) { }

        @Override
        public void onTabReselected(TabLayout.Tab tab) { }
    });

or you can also do this directly for the last line

tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager) {
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        viewPager.setCurrentItem(tab.getPosition(), false);
    }
});
Impair answered 16/7, 2017 at 14:20 Comment(0)
L
4

Actually you are dealing with Scrolling issue. Yes. the thing is, TabLayout Extends HorizontalScrollView. try Something like this.

public class CustomTabLayout extends TabLayout {

public CustomTabLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}

public CustomTabLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public CustomTabLayout(Context context) {
    super(context);
    init(context);
}

void init(Context ctx){

}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    // Do not allow touch events.
    return false;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    // Do not allow touch events.
    return false;
}

}
Larimor answered 1/2, 2017 at 9:49 Comment(1)
The thing is, if I do override these methods, them I will have to implement all select and scroll behaviour for myself. And providing that most of the TabLayout methods are private, this approach will have to use Reflection API too. But it is a possibility though.Teplica
M
1

I think it's worth using TabLayoutMediator

and it will look like this

TabLayoutMediator(tabs, view_pager, true, false) { tab, position ->
        tab.text = ""
}.attach()
Mechanistic answered 19/1, 2021 at 7:22 Comment(0)
S
0

Change your method as below:

private void setStartingSelection(ViewPager viewPager, ProductsPagerAdapter adapter) {
        int tabPosition=0;
        for(int i = 0 ; i < adapter.getCount(); i++){
            String title = (String) adapter.getPageTitle(i);
            if(title.equals(selectedCategory.getName())){
                tabPosition=i;
                break;
            }
        }
        viewPager.setCurrentItem(tabPosition);
    }

I hope this helps you.

Sunday answered 30/1, 2017 at 11:25 Comment(1)
I am sorry, but I fear setting the starting selection does not help here. This scrolling appears not only the first time, but every time when you scroll tabs and select one of themTeplica
T
0

After a lot of search I understood that I need another component which will look like TabLayout, but won't be TabLayout. So I used ViewPagerIndicator.

It is very similar to TabLayout, though it lacks cool selection animations and selected tab indicator animations, which are present in TabLayout. It also doesn't resize text to fit tabs, which is good, and it doesn't resize tabs to fit text either, which is bad (tried all style parameters that I know - could not make it wrap the text).

But it selects tabs just fine and without additional scrolling. AndroidArsenal unfortunately does not contain solutions, which are better than that (at least it didn't when I searched).

Teplica answered 3/2, 2017 at 12:26 Comment(0)
H
0

You can use this custom ViewPager, may be it can help you :)

public class NonSmoothViewPager extends ViewPager {

    private boolean mIsEnabledSwipe = true;

    public NonSmoothViewPager(Context context) {
        super(context);
    }

    public NonSmoothViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setEnabledSwipe(boolean isEnabledSwipe) {
        mIsEnabledSwipe = isEnabledSwipe;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return mIsEnabledSwipe && super.onTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return mIsEnabledSwipe && super.onInterceptTouchEvent(event);

    }

    @Override
    public void setCurrentItem(int item) {
        super.setCurrentItem(item, false);
    }

    @Override
    public void setCurrentItem(int item, boolean smoothScroll) {
        super.setCurrentItem(item, false);
    }
}
Hesperus answered 19/3, 2018 at 3:2 Comment(0)
C
0

try to wrap tablayout in horizontal scoll view like this

        <HorizontalScrollView
            android:id="@+id/horizontal_scroll"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/VW_C1">

            <com.google.android.material.tabs.TabLayout
                android:id="@+id/RankList"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@color/white"
                app:tabIndicator="@color/white"
                app:tabMode="scrollable" />

        </HorizontalScrollView>
Chazan answered 2/1, 2023 at 6:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.