Tablayoutを使用して、30個のスクロール可能なタブを作成しました。
したがって、最初の3つのタブは画面に表示され、残りのタブは非表示になり、スワイプジェスチャーを使用してスクロールできます。
問題は、プログラムで最後のタブを選択しているときに表示されないことです(タブレイアウトが最後のタブにスクロールされません)。
最後のタブにスクロールするようにtablayoutを作成するにはどうすればよいですか?
私は解決策を見つけました。
最初に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();
}
});
}
上記の答えはうまくいきません。最初にアジラーデロが言及したように、mTabLayout.getWidth()
を使用しないでください。必要なもの(スクロール先の子の位置)と更新されたソリューションTabLayoutのバグ( here と報告)のために常に機能するとは限りませんが、回避策は簡単です。
TabLayoutのタブはTabLayoutの直接の子ではないため、次を使用して1レベル深くする必要があります。
_((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();
_
注:レイアウトがdrれた後にこれらのメソッドを呼び出していることを確認してください(onCreateではなくonResumeなど)
お役に立てれば。
最後のタブを選択するには、tabLayout.getTabAt(X).select();を使用します。 Xは最後のタブインデックスです
new Handler().postDelayed(
new Runnable() {
@Override public void run() {
mTabLayout.getTabAt(TAB_NUMBER).select();
}
}, 100);
TabLayoutとその子が実際に測定および描画される前にtab.select()
を呼び出していますか?その場合、TabLayoutはtab.select()
(またはKayvan Nの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();
}
});
}
}
}
提案があればコメントしてください。
tab = tabLayout.getSelectedTabPosition();
tab++;
TabLayout.Tab tabs = tabLayout.getTabAt(tab);
if (tabs != null) {
tabs.select();
}
else {
tabLayout.getTabAt(0).select();
}
クリックイベントで次のタブが必要な場合、このコードを実際に使用します
これは非常に遅く来ているので、これが答えになるかどうかは疑問です。 Xamarinを使用して実際にC#で実現しました。
tabs.GetChildAt(0).Selected = true;
viewPager.SetCurrentItem(0, true);
viewpager.setItem(position)
はタブの位置も設定する必要があります
このソリューションは私のために働いた。私の状況は少し異なります。私の場合、ViewPagerでTabLayoutを使用し、さらにビューを追加して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のコードです。
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;
}
}
TabLayout
をViewPager
と組み合わせて使用する場合(これは一般的です)、アクティビティのonCreate()
メソッドに次を追加するだけです:
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout);
一部のタブが表示されていないことは、tabMode属性がapp:tabMode="scrollable"
に設定されていることを示しています。
以下のコードスニペットは私のために機能します
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()でウィジェットが測定されていないため、呼び出しを延期する必要があります。レイアウトが完了するまで。