web-dev-qa-db-ja.com

TabLayoutはカスタムビューでタブコンテンツを更新します

新しいマテリアルデザインのTabLayoutを使用していますが、問題があります。タブが作成されると、カスタムビューのタブコンテンツを更新できません。

PagerAdapter内のメソッドを次のように単純化できます。

public View setTabView(int position, boolean selected) {
    View v = LayoutInflater.from(context).inflate(R.layout.default_tab_view, null);
    tv = (TextView) v.findViewById(R.id.tabTextView);
    if(selected)
        tv.setText("SELECTED");
    else 
        tv.setText("UNSELECTED");       
    return v;
}

アクティビティでは、次の方法でコードを簡素化できます。

TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
tabLayout.setupWithViewPager(pager);
for (int i = 0; i < tabLayout.getTabCount(); i++) {
    boolean isFirstTab = i == 0;
    TabLayout.Tab tab = tabLayout.getTabAt(i);
    View v;
    v = adapter.setTabView(i, isFirstTab);
    v.setSelected(isFirstTab);
    tab.setCustomView(v);
}

tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        adapter.setTabView(tab.getPosition(), true);
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {
        adapter.setTabView(tab.getPosition(), false);
    }

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

    }
});

タブのタイトルはアプリの起動時に設定されますが、タブを変更してもコンテンツは変わりません。

26

OKAndroidデザインサポートライブラリv22のバグだと思います。

あなたはコンテンツの変化について話しているのに、テキストの色を変えることができないからです。タブが作成され、レイアウトを変更しても反映されません。

そして、私はあなたのコードを見たように、setCustomViewを使用してカスタムレイアウトを与えています。テキストを変更するには、メソッドsetTabView()を再度呼び出します。その代わりに、レイアウトを変更できるようにgetCustomView()メソッドが必要です。 TabLayout.Tab.getCustomViewにはメソッドがありますが、識別子がなく、このバグを報告しています。

https://code.google.com/p/Android/issues/detail?id=177492

[2015年8月7日更新]

最後に、バグはAndroidバグソーストラキングによって受け入れられ、Future Releaseとマークされます。したがって、バグはありません。さらに将来のライブラリに存在し、メソッドgetCustomView()を使用して、カスタムビューを簡単に取得できます。

[2015年8月18日更新]

最後に、バグは解決されましたv23サポートlibsでリリースされました。 SDKマネージャーを使用してサポートライブラリを更新するだけで、getCustomView()がパブリックになります。

gradleでこの行を変更するだけです

compile 'com.Android.support:design:23.0.0'

コンパイルして、ターゲットSDKが23に設定されていることを確認してください。

私のためにうまく機能している私のコードを確認してください

TabLayout.Tab tab=tabLayout.getTabAt(position);         
View view=tab.getCustomView();         
TextView txtCount= (TextView) 
view.findViewById(R.id.txtCount);         
txtCount.setText(count+"");
47
Moinkhan

わかりました。次のサポートライブラリバージョンを待つ時間がなかったからといって、非常に難しい解決策を見つけたかもしれません。私がやったことは次のとおりです。

  1. ポケットベルアダプターをTabLayoutに設定しますtabLayout.setTabsFromPagerAdapter(pagerAdapter);
  2. ViewPagerにリスナーを追加します

    _    customViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }
    
        @Override
        public void onPageSelected(int position) {
            tabLayout.getTabAt(position).select();
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
        }
    });
    _
  3. TabLayoutにリスナーを追加します

    _tabLayout.setOnTabSelectedListener(new
    TabLayout.OnTabSelectedListener() {
    
        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            if (!isTabUpdating) {
                isTabUpdating = true;
                final int pos = tab.getPosition();
                customViewPager.setCurrentItem(pos);
    
                // Clears and populates all tabs
                tabLayout.setTabsFromPagerAdapter(pagerAdapter);
                invalidateTabs(pos);
            }
        }
    
        @Override
        public void onTabUnselected(TabLayout.Tab tab) {
        }
    
        @Override
        public void onTabReselected(TabLayout.Tab tab) {
            if (!isTabUpdating) {
                isTabUpdating = true;
                final int pos = tab.getPosition();
                customViewPager.setCurrentItem(pos);
    
                // Clears and populates all tabs
                tabLayout.setTabsFromPagerAdapter(pagerAdapter);
                invalidateTabs(pos);
            }
        }
    });
    _
  4. すべてのタブを再描画するメソッドを追加します

    _private void invalidateTabs(int selected) {
      for (int i = 0; i < tabLayout.getTabCount(); i++) {
          tabLayout.getTabAt(i).setCustomView(pagerAdapter.getTabView(i, i == selected));
      }
      isTabUpdating = false;
    }
    _

わかりましたので、少し教えてください。まず、なぜsetupWithViewPagerの代わりにsetTabsFromPagerAdapter()を使用したのか疑問に思うかもしれません。最初はsetupWithViewPagerを使用していましたが、どういうわけか私のポケットベルで正しく機能せず、最初のアイテムを選択できませんでした。

2番目に認めるのは、タブを選択するたびにすべてのタブを削除することです。まあ、それはちょっとした簡単な問題でした。Tab.setCustomView(View)を呼び出すとI Android sources)が表示され、ビューの親をチェックし、nullでない場合はすべての子ビューを削除します。ただし、新しくインスタンス化されたアイテムを渡す場合、古いビューを置き換える代わりに別のビューを追加します。

_    View custom = tab.getCustomView();
        if(custom != null) {
            ViewParent icon = custom.getParent();
            if(icon != this) {
                if(icon != null) {
                    // You wont get here
                    ((ViewGroup)icon).removeView(custom);
                }

                this.addView(custom);
            }
     ...
_

だから、私はすべてのリスナーを自分で設定し、ページ/タブが変更されるたびにすべてのタブを再作成することになりました。それは良い解決策ではありませんが、Googleがライブラリを更新するのを待つことができない限り、これがおそらくそのような効果を達成する唯一の解決策です。 (なぜこれがそんなに複雑なのか疑問に思っている場合-カスタムビュー(テキスト+画像)のタブが必要で、ビュープロパティ(フォントの色、画像)を変更できる選択されている/選択されていない)

ところで-これは4番目のステップからのgetTabView(...)メソッドです:

_public View getTabView(int pos, boolean isSeleted) {
    View tabview = ((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout
                    .tab_sessioninfo,
            null, false);
    final ImageView ivTabIcon = (ImageView) tabview.findViewById(R.id.iv_tab_icon);
    final TextView tvTabTittle = (TextView) tabview.findViewById(R.id.tv_tab_title);

    if (isSeleted) {
        tvTabTittle.setTextColor(context.getResources().getColor(R.color.tab_indicator));
    }

    switch (pos) {
        case 0:
            tvTabTittle.setText("1st Tab");
            ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon1_selected : R.drawable.ic_icon1);
            break;

        case 1:
            tvTabTittle.setText("2nd Tab");
            ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon2_selected : R.drawable.ic_icon2);
            break;

        case 2:
            tvTabTittle.setText("3rd Tab");
            ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon3_selected : R.drawable.ic_icon3);
            break;
    }

    return tabview;
}
_

追伸あなたがこれらすべてのためのより良い解決策を知っているなら、私に知らせてください!

[〜#〜] update [〜#〜]

Reflectionを使用すると、より優れたソリューションにアプローチできます。

  1. 簡単セットアップ

    _tabLayout.setupWithViewPager(customViewPager);
    customViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }
    
        @Override
        public void onPageSelected(int position) {
            for (int i = 0; i <tabLayout.getTabCount(); i++){
                updateTab(tabLayout.getTabAt(i), position == i);
            }
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
        }
    });
    _
  2. 更新タブ

    _private void updateTab(TabLayout.Tab tab, boolean isSelected){
      Method method = null;
      try {
          method = TabLayout.Tab.class.getDeclaredMethod("getCustomView", null);
          method.setAccessible(true);
    
          View tabview = (View) method.invoke(tab, null);
    
          final ImageView ivTabIcon = (ImageView) tabview.findViewById(R.id.iv_tab_icon);
          final TextView tvTabTittle = (TextView) tabview.findViewById(R.id.tv_tab_title);
    
          if (isSeleted) {
              tvTabTittle.setTextColor(context.getResources().getColor(R.color.tab_indicator));
          }
    
          switch (pos) {
          case 0:
                tvTabTittle.setText("1st Tab");
                ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon1_selected : R.drawable.ic_icon1);
                break;
    
          case 1:
                tvTabTittle.setText("2nd Tab");
                ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon2_selected : R.drawable.ic_icon2);
                break;
    
          case 2:
                tvTabTittle.setText("3rd Tab");
                ivTabIcon.setImageResource(isSeleted ? R.drawable.ic_icon3_selected : R.drawable.ic_icon3);
                break;
          }
    
          tab.setCustomView(tabview);
      } catch (Exception e) {
          e.printStackTrace();
      }
    }
    _

[〜#〜] update [〜#〜]

新しいサポートライブラリにはgetCustomView()のパブリックメソッドがあるため、リフレクションはもう必要ありません!

7
Paul Freez

Answer を見て、期待どおりにレイアウトを設定する必要があります。タブの内容を変更する場合は、Tab.setOnTabSelectedListener()で変更を加えます。

tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        if(tab.getPosition()==1){
                tabLayout.setTabTextColors(ContextCompat.getColor(getActivity(), R.color.unselected_tab),ContextCompat.getColor(getActivity(), R.color.tab_selection));
            }else{
                tabLayout.setTabTextColors(ContextCompat.getColor(getActivity(), R.color.unselected_tab),ContextCompat.getColor(getActivity(), R.color.white));

            }

 // same thing goes with other tabs too
 // Just change your tab text on selected/deselected as above

    }

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

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

    }
});
0
Tara

私のためにうまく機能している私のコードを確認してください

TabLayout.Tab tab=tabLayout.getTabAt(position);         
View view=tab.getCustomView();         
TextView txtCount= (TextView) view.findViewById(R.id.txtCount);         
txtCount.setText(count+"");
0
Dalvendra Singh