Как прокручивать tablayout программно-Android

Я создал 30 прокручиваемых вкладок с помощью tablayout.

Итак, первые три вкладки видны на экране, а остальные невидимы, которые можно прокручивать с помощью жеста салфетки.

проблема в том, когда я выбираю последнюю вкладку программно, но она не отображается (макет вкладки не прокручивается до последней вкладки).

Как я могу сделать tablayout для прокрутки до последней вкладки?

спасибо заранее.

11 ответов


Я нашел решение.

сначала я нашел ширину tablayout и прокрутил ее x-позицию на ширину и вызвал метод select() последней вкладки.

и он отлично работает.

ниже код.

mTabLayout.setScrollX(mTabLayout.getWidth());
mTabLayout.getTabAt(lastTabIndex).select();

Обновлено:

Если выше не работает, вы также можете использовать приведенный ниже код, он также работает нормально.

new Handler().postDelayed(
        new Runnable() {
            @Override public void run() {
                mTabLayout.getTabAt(TAB_NUMBER).select();
            }
        }, 100);

Я нашел это решение для меня:

    TabLayout tabLayout = activity.getTabLayout();
    tabLayout.setSmoothScrollingEnabled(true);
    tabLayout.setScrollPosition(targetChannelPosition, 0f, true);

кроме того, если вы получаете эту ошибку: "только исходный поток, который создал вид иерархии может коснуться его видом.", вы можете использовать этот код для запуска в потоке Ui:

    // find a way to get the activity containing the tab layout
    TabLayout tabLayout = activity.getTabLayout();
    activity.runOnUiThread(new Runnable()
    {
        @Override
        public void run()
        {
            TabLayout.Tab tab = tabLayout.getTabAt(targetChannelPosition);
            tab.select();
        }
    });

напишите этот метод в пользовательском tablayout (ваш собственный макет, который расширяет tablayout). Таким образом, в будущем вы можете использовать этот метод всякий раз, когда вам нужен instad дублирования кода

public void selectTabAt(int tabIndex) {
        if (tabIndex >= 0 && tabIndex < getTabCount() && getSelectedTabPosition() != tabIndex) {
            final Tab currentTab = getTabAt(tabIndex);
            if (currentTab != null) {
                this.post(new Runnable() {
                    @Override
                    public void run() {
                        currentTab.select();
                    }
                });
            }
        }
    }

Если вы не хотите использовать CustomLayout. вы можете просто сделать это

final Tab currentTab = mTabLayout.getTabAt(tabIndex);
if(currentTab != null){
     mTabLayout.post(new Runnable() {
                    @Override
                    public void run() {
                        currentTab.select();
                    }
                });
}

приведенный выше ответ не будет работать, потому что сначала, как сказал agirardello, вы не должны использовать mTabLayout.getWidth() поскольку он не возвращает то, что нам нужно (это позиция ребенка, которого вы хотите прокрутить), и обновленное решение не всегда работает из-за ошибки в TabLayout (сообщается здесь), но обойти это просто.

вкладки на tabLayout не являются прямыми детьми TabLayout, поэтому нам нужно перейти на один уровень глубже, используя

((ViewGroup) mTabLayout.getChildAt(0)).getChildAt(YOUR_DESIRED_TAB_INDEX).getRight()

в единственный ребенок tabLayout является TabLayout.SlidingTabStrip, который также ViewGroup и getRight() даст нам самое правильное положение нашей желаемой вкладки. Таким образом, прокрутка до этой позиции даст нам то, что мы желаем. Вот полный код:

int right = ((ViewGroup) mTabLayout.getChildAt(0)).getChildAt(4).getRight();
mTabLayout.scrollTo(right,0);
mTabLayout.getTabAt(4).select();

Примечание: убедитесь, что вы вызываете эти методы после того, как макет был утоплен (например, onResume, а не onCreate)

надеюсь, что это помогает.


выбрать последнюю вкладку, используйте tabLayout.getTabAt (X).select (); где X-последний индекс вкладки


ты называешь tab.select() до того, как TabLayout и его дети были фактически измерены и нарисованы? Если это так, ваш TabLayout не будет анимироваться для выбора с помощью tab.select() (или предложение Кайвана Н scrollTo()). Использование обработчика, вероятно, будет работать, но это не идеальное решение.

при условии, что макет еще не был выложен, a ViewTreeObserver позволит вам перейти на выбранную вкладку после завершения процесса компоновки.

private void scrollToTabAfterLayout(final int tabIndex) {
    if (getView() != null) {
        final ViewTreeObserver observer = mTabLayout.getViewTreeObserver();

        if (observer.isAlive()) {
            observer.dispatchOnGlobalLayout(); // In case a previous call is waiting when this call is made
            observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                        observer.removeOnGlobalLayoutListener(this);
                    } else {
                        //noinspection deprecation
                        observer.removeGlobalOnLayoutListener(this);
                    }

                    mTabLayout.getTabAt(tabIndex).select();

                }
            });
        }
    }
}

пожалуйста комментарий если у вас есть какие-либо предложения.


new Handler().postDelayed(
    new Runnable() {
        @Override public void run() {
            mTabLayout.getTabAt(TAB_NUMBER).select();
        }
    }, 100);

viewpager.setItem(position) следует также установить положение вкладки


это решение работает для меня. Моя ситуация немного отличается; в моем случае я использую TabLayout с ViewPager и добавляю больше представлений и вызываю notifyDataSetChange().

решение состоит в том, чтобы установить обратный вызов на наблюдателе TabLayout и прокрутить, когда дети фактически добавляются в TabLayout. Вот мой пример:

/**
    Keep in mind this is how I set my TabLayout up...

    PagerAdapter pagerAdapter = new PagerAdapter(...);
    ViewPager pager = (ViewPager)findViewById(...);
    pager.setAdapter(pagerAdapter);

    TabLayout tabLayout = (TabLayout)findViewById(...);
    tabLayout.setupWithViewPager(pager);
*/
public void loadTabs(String[] topics) {
    animateTabsOpen(); // Irrelevant to solution

    // Removes fragments from ViewPager
    pagerAdapter.clear();

    // Adds new fragments to ViewPager
    for (String t : topics)
         pagerAdapter.append(t, new TestFragment());

    // Since we need observer callback to still animate tabs when we
    // scroll, it is essential to keep track of the state. Declare this
    // as a global variable
    scrollToFirst = true;

    // Alerts ViewPager data has been changed
    pagerAdapter.notifyOnDataSetChanged();

    // Scroll to the beginning (or any position you need) in TabLayout
    // using its observer callbacks
    tabs.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            /**
                 We use onGlobalLayout() callback because anytime a tab
                 is added or removed the TabLayout triggers this; therefore,
                 we use it to scroll to the desired position we want. In my
                 case I wanted to scroll to the beginning position, but this
                 can easily be modified to scroll to any position.
             */
            if (scrollToFirst) {
                tabs.getTabAt(0).select();
                tabs.scrollTo(0, 0);
                scrollToFirst = false;
            }
        }
    });
}

вот мой код для PagerAdapter, если вам это тоже нужно lol:

public class PagerAdapter extends FragmentStatePagerAdapter {
    private List<Fragment> fragments;
    private List<String> titles;


    public PagerAdapter(FragmentManager fm) {
        super(fm);
        this.fragments = new ArrayList<>();
        this.titles = new ArrayList<>();
    }

    /**
     * Adds an adapter item (title and fragment) and
     * doesn't notify that data has changed.
     *
     * NOTE: Remember to call notifyDataSetChanged()!
     * @param title Fragment title
     * @param frag Fragment
     * @return This
     */
    public PagerAdapter append(String title, Fragment frag) {
        this.titles.add(title);
        this.fragments.add(frag);
        return this;
    }

    /**
     * Clears all adapter items and doesn't notify that data
     * has changed.
     *
     * NOTE: Rememeber to call notifyDataSetChanged()!
     * @return This
     */
    public PagerAdapter clear() {
        this.titles.clear();
        this.fragments.clear();
        return this;
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return titles.get(position);
    }

    @Override
    public int getCount() {
        return fragments.size();
    }

    @Override
    public int getItemPosition(Object object) {
        int position = fragments.indexOf(object);
        return (position >= 0) ? position : POSITION_NONE;
    }
}

интересно, будет ли это ответ актуальным, так как он придет очень поздно. я действительно достиг этого в C#, используя Xamarin.

tabs.GetChildAt(0).Selected = true;
 viewPager.SetCurrentItem(0, true);

если TabLayout используется в сочетании с ViewPager, что является общим, просто добавьте следующее в onCreate() метод в вашей деятельности:

tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout);

что некоторые вкладки не показаны указывает атрибут tabMode имеет значение app:tabMode="scrollable".