转载

如何手动修改TabPageIndicator的title的解决办法

前言

今天要讲述的是关于 TabPageIndicator 这个控件,使用场合就是类似网易新闻的 tab 栏,乍一看没什么稀奇的,但是最近遇到的需求是在 tab 显示完成后,点击其他按钮要动态的去修改对应的 tabtitle 。然后我也是陷入了一个坑,因为大家 look

如何手动修改TabPageIndicator的title的解决办法

这是我们 TabPageIndicatortabtitle 的来源,我了个去,这不是在初始化的时候完成的吗,那我们怎么在不刷新整体的适配器的情况去完成这个事情,请接着往下看,要看源码了咯。

正文

理解初始化

首先让我们看看为什么 getPageTitle 这个方法可以初始化 TabPageIndicatortitle 。我先把 TabPageIndicator 的源码贴出来先

/*  * Copyright (C) 2011 The Android Open Source Project  * Copyright (C) 2011 Jake Wharton  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package com.viewpagerindicator;  import android.content.Context; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import android.widget.TextView;  import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;  /**  * This widget implements the dynamic action bar tab behavior that can change  * across different configurations or circumstances.  */ public class TabPageIndicator extends HorizontalScrollView implements PageIndicator {     /** Title text used when no title is provided by the adapter. */     private static final CharSequence EMPTY_TITLE = "";      /**      * Interface for a callback when the selected tab has been reselected.      */     public interface OnTabReselectedListener {         /**          * Callback when the selected tab has been reselected.          *          * @param position Position of the current center item.          */         void onTabReselected(int position);     }      private Runnable mTabSelector;      private final OnClickListener mTabClickListener = new OnClickListener() {         public void onClick(View view) {             TabView tabView = (TabView)view;             final int oldSelected = mViewPager.getCurrentItem();             final int newSelected = tabView.getIndex();             mViewPager.setCurrentItem(newSelected);             if (oldSelected == newSelected && mTabReselectedListener != null) {                 mTabReselectedListener.onTabReselected(newSelected);             }         }     };      private final IcsLinearLayout mTabLayout;      private ViewPager mViewPager;     private OnPageChangeListener mListener;      private int mMaxTabWidth;     private int mSelectedTabIndex;      private OnTabReselectedListener mTabReselectedListener;      public TabPageIndicator(Context context) {         this(context, null);     }      public TabPageIndicator(Context context, AttributeSet attrs) {         super(context, attrs);         setHorizontalScrollBarEnabled(false);          mTabLayout = new IcsLinearLayout(context, R.attr.vpiTabPageIndicatorStyle);         addView(mTabLayout, new ViewGroup.LayoutParams(WRAP_CONTENT, MATCH_PARENT));     }      public void setOnTabReselectedListener(OnTabReselectedListener listener) {         mTabReselectedListener = listener;     }      @Override     public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);         final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY;         setFillViewport(lockedExpanded);          final int childCount = mTabLayout.getChildCount();         if (childCount > 1 && (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) {             if (childCount > 2) {                 mMaxTabWidth = (int)(MeasureSpec.getSize(widthMeasureSpec) * 0.8f);             } else {                 mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2;             }         } else {             mMaxTabWidth = -1;         }          final int oldWidth = getMeasuredWidth();         super.onMeasure(widthMeasureSpec, heightMeasureSpec);         final int newWidth = getMeasuredWidth();          if (lockedExpanded && oldWidth != newWidth) {             // Recenter the tab display if we're at a new (scrollable) size.             setCurrentItem(mSelectedTabIndex);         }     }      private void animateToTab(final int position) {         final View tabView = mTabLayout.getChildAt(position);         if (mTabSelector != null) {             removeCallbacks(mTabSelector);         }         mTabSelector = new Runnable() {             public void run() {                 final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2;                 smoothScrollTo(scrollPos, 0);                 mTabSelector = null;             }         };         post(mTabSelector);     }      @Override     public void onAttachedToWindow() {         super.onAttachedToWindow();         if (mTabSelector != null) {             // Re-post the selector we saved             post(mTabSelector);         }     }      @Override     public void onDetachedFromWindow() {         super.onDetachedFromWindow();         if (mTabSelector != null) {             removeCallbacks(mTabSelector);         }     }      private void addTab(int index, CharSequence text, int iconResId) {         final TabView tabView = new TabView(getContext());         tabView.mIndex = index;         tabView.setFocusable(true);         tabView.setOnClickListener(mTabClickListener);         tabView.setText(text);          if (iconResId != 0) {             tabView.setCompoundDrawablesWithIntrinsicBounds(iconResId, 0, 0, 0);         }          mTabLayout.addView(tabView, new LinearLayout.LayoutParams(0, MATCH_PARENT, 1));     }      @Override     public void onPageScrollStateChanged(int arg0) {         if (mListener != null) {             mListener.onPageScrollStateChanged(arg0);         }     }      @Override     public void onPageScrolled(int arg0, float arg1, int arg2) {         if (mListener != null) {             mListener.onPageScrolled(arg0, arg1, arg2);         }     }      @Override     public void onPageSelected(int arg0) {         setCurrentItem(arg0);         if (mListener != null) {             mListener.onPageSelected(arg0);         }     }      @Override     public void setViewPager(ViewPager view) {         if (mViewPager == view) {             return;         }         if (mViewPager != null) {             mViewPager.setOnPageChangeListener(null);         }         final PagerAdapter adapter = view.getAdapter();         if (adapter == null) {             throw new IllegalStateException("ViewPager does not have adapter instance.");         }         mViewPager = view;         view.setOnPageChangeListener(this);         notifyDataSetChanged();     }      public void notifyDataSetChanged() {         mTabLayout.removeAllViews();         PagerAdapter adapter = mViewPager.getAdapter();         IconPagerAdapter iconAdapter = null;         if (adapter instanceof IconPagerAdapter) {             iconAdapter = (IconPagerAdapter)adapter;         }         final int count = adapter.getCount();         for (int i = 0; i < count; i++) {             CharSequence title = adapter.getPageTitle(i);             if (title == null) {                 title = EMPTY_TITLE;             }             int iconResId = 0;             if (iconAdapter != null) {                 iconResId = iconAdapter.getIconResId(i);             }             addTab(i, title, iconResId);         }         if (mSelectedTabIndex > count) {             mSelectedTabIndex = count - 1;         }         setCurrentItem(mSelectedTabIndex);         requestLayout();     }      @Override     public void setViewPager(ViewPager view, int initialPosition) {         setViewPager(view);         setCurrentItem(initialPosition);     }      @Override     public void setCurrentItem(int item) {         if (mViewPager == null) {             throw new IllegalStateException("ViewPager has not been bound.");         }         mSelectedTabIndex = item;         mViewPager.setCurrentItem(item);          final int tabCount = mTabLayout.getChildCount();         for (int i = 0; i < tabCount; i++) {             final View child = mTabLayout.getChildAt(i);             final boolean isSelected = (i == item);             child.setSelected(isSelected);             if (isSelected) {                 animateToTab(item);             }         }     }      @Override     public void setOnPageChangeListener(OnPageChangeListener listener) {         mListener = listener;     }      public OnPageChangeListener getOnPageChangeListener() {         return mListener;     }      private class TabView extends TextView {         private int mIndex;          public TabView(Context context) {             super(context, null, R.attr.vpiTabPageIndicatorStyle);         }          @Override         public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {             super.onMeasure(widthMeasureSpec, heightMeasureSpec);              // Re-measure if we went beyond our maximum size.             if (mMaxTabWidth > 0 && getMeasuredWidth() > mMaxTabWidth) {                 super.onMeasure(MeasureSpec.makeMeasureSpec(mMaxTabWidth, MeasureSpec.EXACTLY),                         heightMeasureSpec);             }         }          public int getIndex() {             return mIndex;         }     } }

这是源码不是很长,是为了方便看文章的人自己可以对照源码去看,先看这里

如何手动修改TabPageIndicator的title的解决办法

我们是在这里接收外部的 pageTitle ,然后再看 addTab(i,title,iconResId) 又做了什么

如何手动修改TabPageIndicator的title的解决办法

在这个方法中我们生成了 TabView ,并将 title 赋值给他,然后加入到 mTabLayout 容器中,那么让我们大概了解一下 TabView 是什么

如何手动修改TabPageIndicator的title的解决办法

嗯,我们看到了是 TextView 的子类,自此我们应该能了解为什么能通过重写 getPageTitle 来初始化 TabPageIndicatortitle 了。

深度分析结构

经过前面的分析我们知道了初始化的大概,那么如果我们需要自己动态改变他的内部元素的属性的时候,我们就需要更深入的分析, TabPageIndicator 到底是什么,他的内部结构时怎么构成的。

首先

public class TabPageIndicator extends HorizontalScrollView implements PageIndicator

他是个 HorizontalScrollView

public TabPageIndicator(Context context, AttributeSet attrs) {         super(context, attrs);         setHorizontalScrollBarEnabled(false);          mTabLayout = new IcsLinearLayout(context, R.attr.vpiTabPageIndicatorStyle);         addView(mTabLayout, new ViewGroup.LayoutParams(WRAP_CONTENT, MATCH_PARENT));     }

构造器里面我们可以知道他的结构是在 HorizontalScrollView 里面塞入了一个 IcsLinearLayout (一种 LinearLayout 子类控件容器)。

然后在刚才的 addTab(i,title,iconResId) ,我们也看到了

private void addTab(int index, CharSequence text, int iconResId) {         final TabView tabView = new TabView(getContext());         tabView.mIndex = index;         tabView.setFocusable(true);         tabView.setOnClickListener(mTabClickListener);         tabView.setText(text);          if (iconResId != 0) {             tabView.setCompoundDrawablesWithIntrinsicBounds(iconResId, 0, 0, 0);         }          mTabLayout.addView(tabView, new LinearLayout.LayoutParams(0, MATCH_PARENT, 1));     }

他会在 IcsLinearLayout 里面塞入一个个 TabView 控件(就是 tab 栏你们看到的一个个元素,:smile:),这样我们就彻底明白了是什么结构了。

解决办法

既然已经知道结构了,那我们就开始解决如何修改属性的问题吧,首先要找到那个最底层的那个 TabView 元素,并没有提供直接的方法获取,那相信大家知道 android 的界面结构其实就是容器包裹的方式

((TextView) ((IcsLinearLayout) tabIndicator.getChildAt(0)).getChildAt(0)).setText("0检查项("+selectedExamineItems.size()+")");

第一个 getChildAt(0) 就是找到 IcsLinearLayout 容器,第二个 getChildAt(0) 就是找到 IcsLinearLayout 第一个 TabView ,我将它强制转换为 TextView ,因为本来就是 TextView 的子类,没毛病。这样一来我们就做到手动修改 title 了。但是别高兴太早,有瑕疵(当你修改 title 的内容的时候如果是增加内容字数 TabView 会变长,但是你再减少字数的时候, shit ,它不会变短了,这太坑爹了),还有 IcsLinearLayout 类默认是 private 需要改为 public 不然这里没法引用,最后请看下面的优化方案。

优化方案

想看三张图

如何手动修改TabPageIndicator的title的解决办法

如何手动修改TabPageIndicator的title的解决办法

如何手动修改TabPageIndicator的title的解决办法

没有错我提供的思路方案就是手动修改 TabView 的宽度,我先将一个 padding 设置跟 TabPageIndicator 的主题设置一样的 TextView 传入我们的内容,这样得到的宽度就是我们最终需要设置的宽度了,完美!

总结

百度不是万能的,作为一个研发者,还是保持阅读源码,提高自己分析能力才是出路,:smile: bye!

原文  https://segmentfault.com/a/1190000005964707
正文到此结束
Loading...