TabLayout源码解析及相关问题解决

一、内部组成元素及分析

  1. TabLayout的三个基本组成元素:Tab、TabView、SlidingTabStrip
  2. TabLayoutOnPageChangeListener和ViewPagerOnTabSelectedListener实现了ViewPager类的两个接口,作用是监听ViewPager页面改变和Tab选中状态。
  3. PagerAdapterObserver为观察者监控PagerAdapter数据变化。
  4. 所以在自定义TabLayout前,先设计好Tab模式,并且官方扩展了一个TabView子控件件。
  5. 自定义TabLayout的工作,还要通过接口完成和ViewPager的交互,通过PagerAdapterObserver,确保TabLayout能够正常工作。

二、内部类,Tab模型

内部类Tab定义了Tab的成员变量,并提供set和get方法,并封装了tab的属性设置方法,(setIcon、setCustomView)

三、内部类,自定义的TabView

TabView继承自LinearLayout,默认的tab布局,可以同时显示图片和文字;

其构造器设置了TabView在TabLayout中的状态,这些状态属性都是固定的不可变的,所以也决定TabView设置受到限制。

public TabView(Context context) {
    super(context);
    if (mTabBackgroundResId != 0) {
        ViewCompat.setBackground(
                this, AppCompatResources.getDrawable(context, mTabBackgroundResId));
    }
    ViewCompat.setPaddingRelative(this, mTabPaddingStart, mTabPaddingTop,
            mTabPaddingEnd, mTabPaddingBottom); //设置padding
    setGravity(Gravity.CENTER); //居中显示
    setOrientation(VERTICAL); //布局方向
    setClickable(true);//可点击
    ViewCompat.setPointerIcon(this,                                                                                             
            PointerIconCompat.getSystemIcon(getContext(), PointerIconCompat.TYPE_HAND));
}

看源码setCustomView(@LayoutRes int resId) 最终会调用到TabView的update方法中去:

update方法,先判断设置的customView是否为空,是否有父类,移除TabView中默认的组件,分别获取TextView和Icon,如果获取失败,仍然使用默认的组件;

这里要注意,自定义的TextView的ID必须设置为android.R.id.text1,Icon必须设置为android.R.id.icon;因为代码中好像是写死的;

四、SlidingTabStrip,Tab下滑线

这个自定义view SlidingTabStrip是私有内部类,它继承自LinearLayout,作用为获取tab的最宽宽度,设置SlidingTabStrip的宽度,并设置一个动画,随着tab的改变绘制;

因为它是私有的,所以就固定了他的样式只能是简单的直线形式,如果需要特殊样式的下划线,就需要自定义了

SlidingTabStrip。它有一个构造器:

SlidingTabStrip(Context context) {
    super(context);
    setWillNotDraw(false);//重写draw()不起作用时,需要添加这么一句
    mSelectedIndicatorPaint = new Paint();
}

单看这个构造器就知道使用SlidingTabStrip超级简单,在这个构造器源码中,有一个地方需要注意,因为在我们自定义view中会用到,就是setWillNotDraw(false);但看这句的字面意思就不难猜到,双重否定等于肯定,让它进行绘制。当我们自定义的view在onDrow()不起作用时,一种方法是在构造器里设置背景颜色,一种就是添加这句语句。原因可以进一步参考ViewGroup为什么不会调用onDraw

代码结构极易一目了然。在onMeasure()获取最宽tab宽度,并设置为此控件的宽度;在onLayout()进行动画并更新Indicator位置;最后draw()。

 

五,ViewPager的监听器:TabLayoutOnPageChangeListener

这个类是实现ViewPager.OnPageChangeListener的一个内部类,作用是监听到ViewPager页面改变的时候,更新tab和Indicator。首先注意这个类是public,并且被static修饰,static一般用来修饰成员变量或或成员函数,有static修饰内部类有什么特别呢,那就是在外面使用这个类的时候,不需要先new内部类所在的类(如在这里为TabLayout)的实例,可以直接new这个内部类的实例,比如:

TabLayout.TabLayoutOnPageChangeListener listener=new TabLayout.TabLayoutOnPageChangeListener;

 

六,TabLayout的tab选中监听:ViewPagerOnTabSelectedListener

public static class TabLayoutOnPageChangeListener implements ViewPager.OnPageChangeListener {}
public static class ViewPagerOnTabSelectedListener implements TabLayout.OnTabSelectedListener {}

 

除了这个内部类也是public static外,与ViewPager.OnPageChangeListener相对应的是这里实现的是TabLayout.OnTabSelectedListener;这个接口是TabLayout中定义的接口,在这里实现的作用是使TabLayout中的tab能够和ViewPager的pager保持同步。

然后在TabLayout中有一个方法:

 

public void setOnTabSelectedListener(OnTabSelectedListener onTabSelectedListener) {
        mOnTabSelectedListener = onTabSelectedListener;
}

mOnTabSelectedListener是这个内部类ViewPagerOnTabSelectedListener的一个实例,我们使用TabLayout时,就是通过调用这个方法设置tab的监听事件。

 

七,数据监听:PagerAdapterObserver

这是一个观察者,继承自DataSetObserver,DataSetObserver我不多说了,关于介绍推荐Android中的观察者DataSetObservabl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值