TabLayout update tab content with a custom view

后端 未结 4 1050
悲&欢浪女
悲&欢浪女 2021-02-01 03:48

I\'m using TabLayout of the new material design and i have a problem, i can\'t update tab content of a custom view once the tab is created:

I can simplify m

4条回答
  •  长情又很酷
    2021-02-01 04:39

    Well ok, I might have found a very tricky solution just because I didn't have any time to wait for next support-library version. Here's what I did:

    1. Set pager adapter to your TabLayout tabLayout.setTabsFromPagerAdapter(pagerAdapter);
    2. Add listener to your 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. Add listener to your 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. Add method for re-drawing all tabs

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

    Ok, so let me explain know a little bit. First of all, you might wonder why did I used setTabsFromPagerAdapter() instead of setupWithViewPager. In the beginning I used setupWithViewPager but somehow my it didn't work correctly with my pager and the 1st item wasn't been able to be selected.

    The second thing you might admit - every time I'm selecting a tab I'm deleting all of them. Well, that was kind of easy problem, you see I android sources when you call Tab.setCustomView(View) it checks the parent of the view and if it's not null - it removes all childviews. However if you pass newly-instantiated item you'll ADD another view instead of replacing the old one:

        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);
                }
         ...
    

    So, I ended up with setting all listeners by myself and re-creating all tabs every time on page/tab changes. That's NOT good solution, but as far as can't wait for Google to update their lib - this's probably the only solution to achieve such effect. (Just in case you're wondering why is this so complicated - I needed to have Tabs with custom views (text + image) which could change their view-properties (font color, image) when they're selected/unselected)

    BTW - Here's the getTabView(...) method from 4th step:

    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. If you know better solution for all this stuff let me know!

    UPDATE

    Better solution could be approached by using Reflection:

    1. Easy setup

      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 
    2. Update Tab

      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

    New support library has public method for getCustomView(), so you don't need reflection no more!

提交回复
热议问题