Подтвердить что ты не робот

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++) {
    TabLayout.Tab tab = tabLayout.getTabAt(i);
    View v;
    if (i == 0) {
        v = adapter.setTabView(i, true);
        v.setSelected(true);
    } else
        v = adapter.setTabView(i, false);

    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) {

    }
});

Заголовки вкладок устанавливаются правильно, когда приложение запускается, но когда я меняю вкладку, содержимое остается неизменным.

4b9b3361

Ответ 1

Хорошо Я думаю, что это ошибка в библиотеке поддержки дизайна vroid v22.

Потому что вы говорите об изменениях в содержании, но я не могу изменить цвет текста. Как только вкладка будет создана, и если вы измените макет, он не будет отображаться.

И Поскольку я видел ваш код, вы предоставляете настраиваемый макет с помощью setCustomView. и для изменения текста вы снова вызываете метод setTabView(). Вместо этого должен быть метод getCustomView(), чтобы вы могли изменить макет. Существует метод в TabLayout.Tab.getCustomView, но у него нет идентификатора, и я сообщаю об этой ошибке.

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

[Обновить 08-07-2015]

Наконец, ошибка принимается трафиком источника ошибок Android и помечена как Будущая версия. Таким образом, мы можем сказать, что ошибка будет больше не существовать в будущей библиотеке. и мы можем иметь метод getCustomView(), чтобы мы могли легко получить наш пользовательский вид.

[Обновить 18-08-2015]

Наконец, ошибка решена. Выпущена в v23 support 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+"");

Ответ 2

Хорошо, я мог найти очень сложное решение только потому, что у меня не было времени ждать следующей версии поддержки-библиотеки. Вот что я сделал:

  • Установите адаптер пейджера на вкладку TabLayout tabLayout.setTabsFromPagerAdapter(pagerAdapter);
  • Добавить прослушиватель в 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) {
        }
    });
    
  • Добавить слушателя на вкладку 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);
            }
        }
    });
    
  • Добавить метод повторного рисования всех вкладок

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

Хорошо, позвольте мне объяснить немного. Прежде всего, вы можете задаться вопросом, почему я использовал setTabsFromPagerAdapter() вместо setupWithViewPager. В начале я использовал setupWithViewPager, но почему-то это не сработало правильно с моим пейджером, и 1-й элемент не был выбран.

Второе, что вы можете признать - каждый раз, когда я выбираю вкладку, я удаляю все из них. Ну, это была легкая проблема, вы видите, что я источник Android, когда вы вызываете Tab.setCustomView(View), он проверяет родителя представления и, если он не равен 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 обновит их lib - это, вероятно, единственное решение для достижения такого эффекта. (На всякий случай вам интересно, почему это так сложно - мне нужно было иметь вкладки с пользовательскими представлениями (текст + изображение), которые могли бы изменить их свойства вида (цвет шрифта, изображение), когда они будут выбраны/не выбраны)

BTW - здесь метод getTabView(...) с 4-го шага:

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. Если вы знаете лучшее решение для всего этого, дайте мне знать!

UPDATE

К лучшему решению можно подойти с помощью Reflection:

  • Простая настройка

    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) {
        }
    });
    
  • Обновить вкладку

    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(), поэтому вам больше не нужно размышлять!

Ответ 3

пожалуйста, проверьте, что мой код работает нормально для меня

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

Ответ 4

Посмотрите Ответ, вам нужно установить макет, как и ожидалось. Если вы хотите изменить содержимое вкладки, внесите изменения в 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) {

    }
});