TabLayout使用自定义视图更新选项卡内容

时间:2015-06-18 09:16:12

标签: android tabs android-design-library

我正在使用新材料设计的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) {

    }
});

当应用程序启动时,标签的标题设置正确,但当我更改标签时,内容仍然保持不变。

5 个答案:

答案 0 :(得分:46)

好的我认为这是Android设计支持库v22的错误。

因为您正在谈论内容的变化,但我无法更改文本的颜色。创建选项卡后,如果更改布局,则不会反映。

正如我已经看到您的代码,您使用setCustomView提供自定义布局。并且为了更改文本,您再次调用方法setTabView()。而不是应该有方法getCustomView(),以便您可以更改布局。 TabLayout.Tab.getCustomView中有一个方法,但它没有标识符,我已经报告了这个错误。

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

[2015年8月8日更新]

最后bug被android bug source traking接受并标记为 Future Release 。所以我们可以说在未来的库中不再存在bug。 我们可以使用方法getCustomView(),以便我们可以轻松获得自定义视图。

[2015年8月18日更新]

最后,错误已解决 v23 support libs 中发布。 只需使用SDK管理器更新支持库,您就可以将getCustomView()作为公共。

只需在gradle中更改此行

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

并确保将compile和target sdk设置为23。

  

请检查我的代码是否适合我

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

答案 1 :(得分:7)

好吧,我可能找到了一个非常棘手的解决方案,因为我没有时间等待下一个支持库版本。这是我做的:

  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;
    }
    
  5. 好的,让我解释一下。首先,您可能想知道为什么我使用setTabsFromPagerAdapter()而不是setupWithViewPager。在开始时我使用setupWithViewPager,但不知何故,我的浏览器无法正常工作,第一项无法被选中。

    你可能会承认的第二件事 - 每次我选择一个标签时我都会删除它们。好吧,这是一个简单的问题,当你调用Tab.setCustomView(View)时,你看到我的android源代码它会检查视图的父级,如果它不是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);
                }
         ...
    

    因此,我最终自己设置了所有监听器,并且每次在页面/选项卡更改时重新创建所有选项卡。这不是一个好的解决方案,但是等不及谷歌更新他们的lib - 这可能是实现这种效果的唯一解决方案。 (以防万一你想知道为什么这么复杂 - 我需要有自定义视图(文本+图像)的标签,当它们被选中/取消选择时可以改变它们的视图属性(字体颜色,图像) )

    BTW - 这是第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;
    }
    

    P.S。如果你知道所有这些东西的更好解决方案,请告诉我!

    <强>更新

    使用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();
        }
      }
      
    3. <强>更新

      新支持库具有getCustomView()的公共方法,因此您不再需要反射!

答案 2 :(得分:0)

  

请检查我的代码是否适合我

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

答案 3 :(得分:0)

查看您需要设置布局的 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) {

    }
});

答案 4 :(得分:0)

关于这个主题的文档很差。我们可以使用 setCustomView 选项卡的方法来设置自定义视图。以下是一个无需创建自定义适配器的工作示例:

tab_layout.xml

<com.google.android.material.tabs.TabLayout
    android:id="@+id/tabLayout"
    android:layout_width="match_parent"
    android:layout_height="@dimen/tab_height"
    android:background="@color/primary_dark" />

custom_tab_item.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/tab_height"
    android:orientation="horizontal"
    android:padding="@dimen/tab_padding">

    <ImageView
        android:id="@+id/tabIcon"
        android:layout_width="@dimen/tab_icon"
        android:layout_height="@dimen/tab_icon"
        android:layout_centerVertical="true"/>

    <TextView
        android:id="@+id/tabTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@+id/tabIcon"
        android:textColor="@color/white" />

    <TextView
        android:id="@+id/tabSubTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tabTitle"
        android:layout_toEndOf="@+id/tabIcon"
        android:textColor="@color/white" />

</RelativeLayout>

MainActivity.kt

TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
            when (position) {
                0 -> {
                    tab.setCustomView(R.layout.tab_item)
                    tab.customView?.findViewById<ImageView>(R.id.tabIcon)
                        ?.setImageResource(R.drawable.tab1)
                    tab.customView?.findViewById<TextView>(R.id.tabTitle)?.setText(R.string.tab1)
                }
                1 -> {
                    tab.setCustomView(R.layout.tab_item)
                    tab.customView?.findViewById<ImageView>(R.id.tabIcon)
                        ?.setImageResource(R.drawable.tab2)
                    tab.customView?.findViewById<TextView>(R.id.tabTitle)
                        ?.setText(R.string.tab2)
                }
            }
        }.attach()