Как прокрутить табуляцию программно - Android
Я создал 30 прокручиваемых вкладок, используя tablayout.
Таким образом, первые три вкладки видны на экране, а остальные невидимы, и их можно прокручивать с помощью жеста смахивания.
Проблема в том, что я выбираю последнюю вкладку программно, но она не видна (расположение вкладок не прокручивается до последней вкладки).
Как я могу сделать tablayout, чтобы перейти к последней вкладке?
11 ответов
Я нашел решение.
Сначала я нашел ширину табуляции и прокрутил ее позицию по ширине на 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);
Напишите этот метод в вашей пользовательской вкладке (ваш собственный макет, который расширяет вкладку). Таким образом, в будущем вы можете использовать этот метод всякий раз, когда вам нужно дублирование кода
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();
}
});
}
Я нашел это решение для меня:
TabLayout tabLayout = activity.getTabLayout();
tabLayout.setSmoothScrollingEnabled(true);
tabLayout.setScrollPosition(targetChannelPosition, 0f, true);
Кроме того, если вы получаете эту ошибку: "Только исходный поток, создавший иерархию представлений, может касаться его представлений", вы можете использовать этот код для запуска в потоке пользовательского интерфейса:
// 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();
}
});
Ты звонишь tab.select()
до того, как TabLayout и его дочерние элементы были фактически измерены и нарисованы? Если это так, ваш TabLayout не будет анимироваться к выделению с tab.select()
(или предложение Кайвана Н о scrollTo()
). Использование обработчика, вероятно, будет работать, но это не идеальное решение.
Если макет еще не выложен, 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);
Фрагмент кода ниже работает для меня
class TriggerOnceListener(private val v: View, private val block: () -> Unit) : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
block()
v.viewTreeObserver.removeOnPreDrawListener(this)
return true
}
}
fun onCreate() {
val position = ***The tab position you want to scroll to, 29 for your case here***
tabLayout.let { it.viewTreeObserver.addOnPreDrawListener(TriggerOnceListener(it)
{ it.setScrollPosition(position, 0f, true) } ) }
}
Я погрузился в Tab.select() и обнаружил, что Android использует Tablayout.setScrollPosition() для этой прокрутки. А в onCreate() виджеты не были измерены, вам нужно отложить вызов до завершения компоновки.
Приведенный выше ответ не сработает, потому что, как уже говорил Агираделло, вы не должны использовать 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 - индекс последней вкладки
Если твой TabLayout
используется в сочетании с ViewPager
, что обычно, просто добавьте следующее в onCreate()
метод в вашей деятельности:
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout);
То, что некоторые из ваших вкладок не отображаются, означает, что атрибут tabMode установлен в app:tabMode="scrollable"
,
tab = tabLayout.getSelectedTabPosition();
tab++;
TabLayout.Tab tabs = tabLayout.getTabAt(tab);
if (tabs != null) {
tabs.select();
}
else {
tabLayout.getTabAt(0).select();
}
если вы хотите следующую вкладку на событие клика, то используйте этот код его работу идеально
viewpager.setItem(position)
следует также установить положение вкладки
Интересно, будет ли этот ответ актуален, так как он приходит очень поздно. я на самом деле добился этого в C#, используя Xamarin.
tabs.GetChildAt(0).Selected = true;
viewPager.SetCurrentItem(0, true);
Это решение сработало для меня. Моя ситуация немного отличается, хотя; в моем случае я использую 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;
}
}