TabLayout修改

文章目錄

文章修修補補添加了不少,主要分3個時間段

  1. 最早實現,就是在tab切換的時候在下邊畫一條線
  2. 不畫線了,因為看源碼知道線條寬度和tabview一樣的,所以反射修改TabView的寬度
  3. viewPager?.addOnPageChangeListener 根據offset,動態計算view當前的位置,線條應該偏移的位置。
  4. 進化后,想畫啥畫啥,不一定是線條,反正位置都算出來了。

結構分析

QQ截圖20171026091245.png

TabLayout這個導航控件,父類關系如下
public class TabLayout extends HorizontalScrollView
public class HorizontalScrollView extends FrameLayout
里邊子空間的類型
class TabView extends LinearLayout implements OnLongClickListener
private class SlidingTabStrip extends LinearLayout
tablayout的結構圖

QQ截圖20171025161612.png

大概看下源碼,整體布局的添加如下,首先加了一個SlidingTabStrip也就是個線性布局.

 public TabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        ThemeUtils.checkAppCompatTheme(context);

        // Disable the Scroll Bar
        setHorizontalScrollBarEnabled(false);

        // Add the TabStrip
        mTabStrip = new SlidingTabStrip(context);
        super.addView(mTabStrip, 0, new HorizontalScrollView.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));

完事通過綁定viewPager或者直接addTab來添加TabView

private void addTabView(Tab tab) {
        final TabView tabView = tab.mView;
        mTabStrip.addView(tabView, tab.getPosition(), createLayoutParamsForTabs());
    }

添加的tabView的params如下,根據mode和gravity設置為比重為1或是wrap

    private LinearLayout.LayoutParams createLayoutParamsForTabs() {
        final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        updateTabViewLayoutParams(lp);
        return lp;
    }
    private void updateTabViewLayoutParams(LinearLayout.LayoutParams lp) {
        if (mMode == MODE_FIXED && mTabGravity == GRAVITY_FILL) {
            lp.width = 0;
            lp.weight = 1;
        } else {
            lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
            lp.weight = 0;
        }
    }

至于TabView,最上邊也說了也是個線性布局,垂直布局的,簡單看下,默認的布局,里邊添加了一個圖片和一個TextView,自定義的就不說了。添加自定義的也就是把這兩個默認的隱藏,完事add那個自定義的控件到TabView里而已

if (mCustomView == null) {
                // If there isn't a custom view, we'll us our own in-built layouts
                if (mIconView == null) {
                    ImageView iconView = (ImageView) LayoutInflater.from(getContext())
                            .inflate(R.layout.design_layout_tab_icon, this, false);
                    addView(iconView, 0);
                    mIconView = iconView;
                }
                if (mTextView == null) {
                    TextView textView = (TextView) LayoutInflater.from(getContext())
                            .inflate(R.layout.design_layout_tab_text, this, false);
                    addView(textView);
                    mTextView = textView;
                    mDefaultMaxLines = TextViewCompat.getMaxLines(mTextView);
                }
                TextViewCompat.setTextAppearance(mTextView, mTabTextAppearance);
                if (mTabTextColors != null) {
                    mTextView.setTextColor(mTabTextColors);
                }
                updateTextAndIcon(mTextView, mIconView);
            }

說了半天貌似和線條都沒關系,好吧,再看下SlidingTabStrip的代碼。里邊有個onDraw方法,線條就是在這里加的

@Override
        public void draw(Canvas canvas) {
            super.draw(canvas);

            // Thick colored underline below the current selection
            if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {
                canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
                        mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
            }
        }

我們要做的就是如何修改這個線條的左右邊界。下邊先說下老的做法和思路

前提條件

下邊都是為了修改mode=fixed,tabGravity="fill"這種,完事要求線條寬度和文字寬度差不多這種需求。
如果是mode=scollable這種,你要求文字和線條寬度一樣,那么設置如下屬性基本都能滿足需求的

      app:tabMinWidth="2dp"
        app:tabPadding="1dp"
        app:tabPaddingStart="1dp"
        app:tabPaddingEnd="1dp"

簡單分析下,一些默認屬性

mMode = a.getInt(R.styleable.TabLayout_tabMode, MODE_FIXED);
mTabGravity = a.getInt(R.styleable.TabLayout_tabGravity, GRAVITY_FILL);//橫屏的時候默認style里這個是center
        final Resources res = getResources();
        mScrollableTabMinWidth = res.getDimensionPixelSize(R.dimen.design_tab_scrollable_min_width);
  //添加tabview的時候會setminwidth的,就是調用如下方法獲取最小寬度
  //可以看到tab是有個最小寬度的,design_tab_scrollable_min_width手機是72dp,pad之類的是160dp
    private int getTabMinWidth() {
        if (mRequestedTabMinWidth != INVALID_WIDTH) {
            // If we have been given a min width, use it
            return mRequestedTabMinWidth;
        }
        // Else, we'll use the default value
        return mMode == MODE_SCROLLABLE ? mScrollableTabMinWidth : 0;
    }

老的做法和思路

最早比較笨的想法,既然你這線條是畫出來了,那我也畫一個好了,不過因為那線條左右邊界是動態的,想著麻煩,就弄個固定的好了,也就是tab切換的時候才改變線條,少了滑動效果。
我們的需求是線條和文字寬度差不多,那第一步肯定是獲取到文字的寬度了,文字的寬度哪來的,當然是獲取到tabView里的那個TextView的寬度了。

獲取方法有兩種,第一種反射,第二種直接getChildAt

QQ截圖20171025170903.png

看下Tab里的那個mView就是我們要的TabView,里邊就包含有TextView
下邊就是重寫TabLayout,給他畫條線,缺點就是線不能滑動,我們通過監聽tab選中狀態的改變,來invalidate這個布局刷新線條。另外因為有了自己的線條了,所以需要把TabLayout的線條高度設置為0或者線條顏色弄為透明
那個factor就是線條長度和文字寬度的比例,為1就是一樣,比1大就是稍微出去一點

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        TabCheck();
        canvas.drawRect(rectF.left,getHeight()-indicatorHeight,rectF.right,getHeight(),paintLine);

    }
    RectF rectF=new RectF();
    private void TabCheck(){
        try {
            //通過反射獲取那個textView
            Tab tab=getTabAt(getSelectedTabPosition());
            Field field=tab.getClass().getDeclaredField("mView");
            field.setAccessible(true);
            LinearLayout linearLayout= (LinearLayout) field.get(tab);
            /**child1就是tab上的文字控件,第一個是圖片控件,第二個就是這個文本控件*/
            View child1=linearLayout.getChildAt(1);//
            float add=(factor-1)*child1.getWidth()/2;
            rectF.left=linearLayout.getLeft()+child1.getLeft()-add;
            rectF.right=linearLayout.getLeft()+child1.getRight()+add;
        } catch (Exception e) {
            e.printStackTrace();
        }
        //根據整體控件的結構,我們也能拿到那個textView
//        int selectedPosition=getSelectedTabPosition();
//        LinearLayout slidingTabStrip=(LinearLayout)getChildAt(0);
//        LinearLayout tabView= (LinearLayout) slidingTabStrip.getChildAt(selectedPosition);
//        View textView=tabView.getChildAt(1);
    }

新的做法和思路

SlidingTabStrip里有下邊的代碼是來計算線條左右邊距的,根據viewpager的偏移量動態改變
left 和right就是對應的線條的左右點位置

 private void updateIndicatorPosition() {
            final View selectedTitle = getChildAt(mSelectedPosition);
            int left, right;

            if (selectedTitle != null && selectedTitle.getWidth() > 0) {
                left = selectedTitle.getLeft();
                right = selectedTitle.getRight();

                if (mSelectionOffset > 0f && mSelectedPosition < getChildCount() - 1) {
                    // Draw the selection partway between the tabs
                    View nextTitle = getChildAt(mSelectedPosition + 1);
                    left = (int) (mSelectionOffset * nextTitle.getLeft() +
                            (1.0f - mSelectionOffset) * left);
                    right = (int) (mSelectionOffset * nextTitle.getRight() +
                            (1.0f - mSelectionOffset) * right);
                }
            } else {
                left = right = -1;
            }

            setIndicatorPosition(left, right);
        }

既然線條的寬度位置都和tabView有關,那么我們改變tabView的大小即可,默認的tabView的大小就是平分TabLayout的。
這里再強調下,我們的這個自定義只支持下邊的屬性,默認的就是這兩個

app:tabGravity="fill"
app:tabMode="fixed"

完整的代碼如下

import android.content.Context
import android.support.design.widget.TabLayout
import android.util.AttributeSet
import android.view.ViewTreeObserver
import android.widget.LinearLayout
import android.widget.TextView
import java.lang.reflect.Field

/**
 * Created by Sage on 2017/10/25.
 * Description:此控件只適用于 app:tabMode="fixed"
 */
class TabLayoutIndicatorShort : TabLayout {
    constructor(context: Context?) : super(context) {
        initSomeThing()
    }

    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
        initSomeThing()
    }

    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        initSomeThing()
    }


    private fun initSomeThing() {
        viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                viewTreeObserver.removeOnGlobalLayoutListener(this)
                changeIndicator()
            }
        })

    }

    val factor = 1.1f
    fun changeIndicator() {
if(tabCount==0){
            return
        }
        val tabLayout:Class<*> = javaClass.superclass
        var tabStrip: Field? = null
        try {
            tabStrip = tabLayout.getDeclaredField("mTabStrip")
        } catch (e: Exception) {
            e.printStackTrace()
            return
        }
        tabStrip!!.isAccessible = true
        var ll_tab: LinearLayout? = null
        try {
            ll_tab = tabStrip.get(this) as LinearLayout
        } catch (e: Exception) {
            e.printStackTrace()
            return
        }
        /**每個tab的寬,總寬度除以tabCount*/
        val widthTab = width / tabCount
        for (i in 0..ll_tab.childCount - 1) {
            val child = ll_tab.getChildAt(i)
            child.setPadding(0, 0, 0, 0)
            try {
                val tv = (child as LinearLayout).getChildAt(1) as TextView
                var margin = ((widthTab - tv.width * factor) / 2).toInt()
                println("i==" + i + "==widthTab=" + widthTab + "==child w=" + tv.width + "==margin=" + margin)
                if (margin < 0) {
                    margin = 0
                }
                val params = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, tv.width.toFloat())
                params.leftMargin = margin
                params.rightMargin = margin
                child.setLayoutParams(params)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

    }

}

最后看下修改后的效果和原生的效果。

QQ截圖20171026094315.png

原生的線條是平分的,點擊范圍也很大,我們修改后的線條是小了,可點擊范圍也小了。我還是喜歡原生的,可惜啊,很多時候ui設計的都是線條和文字寬度一樣。如果不要求滾動的時候線條動畫,我還是喜歡老的那種,直接畫條線,也不影響點擊范圍。

最后的實現

以前懶得寫啊,最近閑了,就抽空把這個實現吧
先看下效果圖


image.png

移動到一半效果如下圖


image.png

移動了超過一半,如下圖
image.png

移動完成
image.png

簡單說下思路:

隱藏掉原生畫的線條【把顏色設置為透明,或者你把高度弄為0也可以】
然后給viewpager添加監聽滑動的偏移量,我們來計算線條的位置
偏移量在0.5以下,
線條left位置從第一個textview的left位置移動到第一個的中心位置,
線條right位置從第一個textview的right位置移動到第二個textview的中心位置
偏移量0.5到1之間的話,
線條left位置是從第一個textview的中心位置到第二個textview的left位置
線條right位置是從第二個textview的中心位置到第二個textview的rigth位置
庫一直在更新,下邊的使用design庫,新版的androidX也就是material庫,TabLayout的tabIndicatorHeight屬性默認高度沒有了,它是通過一張默認圖片獲取的高度
所以老的代碼,給個默認值,或者xml必須設置一個tabIndicatorHeight的高度才行

 indicotorHeight = a.getDimensionPixelSize(R.styleable.TabLayout_tabIndicatorHeight, 3)

代碼如下

import android.content.Context
import android.graphics.Canvas
import android.support.design.widget.TabLayout
import android.support.v4.view.ViewPager
import android.util.AttributeSet
import android.graphics.Color
import android.graphics.Paint
import android.widget.LinearLayout
import android.graphics.RectF
import android.support.design.R
import android.support.v4.view.ViewCompat

class TabLayoutFixedFill : TabLayout {
    constructor(context: Context) : this(context, null)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
        initAttrs(context,attrs,defStyleAttr)
    }

    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs,R.attr.tabStyle)

    private fun initAttrs(context: Context, attrs: AttributeSet?,defStyleAttr: Int) {
        val a = context.obtainStyledAttributes(attrs, R.styleable.TabLayout,
                defStyleAttr, R.style.Widget_Design_TabLayout)
        indicotorHeight = a.getDimensionPixelSize(R.styleable.TabLayout_tabIndicatorHeight, 0)
        paintLine.color = a.getColor(R.styleable.TabLayout_tabIndicatorColor, 0)
        a.recycle()
        setSelectedTabIndicatorColor(Color.TRANSPARENT)//隱藏掉原生畫的線
    }

    var factor = 1f//線條的長度和文字寬度的比例,因為有的需求是比文字稍微長點。所以這里可以修改
    var indicotorHeight = 2;//線條的高度
    var paintLine = Paint()
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.drawRect(rectIndicator.left, getHeight().toFloat() - indicotorHeight, rectIndicator.right, getHeight().toFloat(), paintLine);
    }

    override fun setupWithViewPager(viewPager: ViewPager?, autoRefresh: Boolean) {
        super.setupWithViewPager(viewPager, autoRefresh)
        viewPager?.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
            override fun onPageScrollStateChanged(state: Int) {
            }

            override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
                updateIndicator(position, positionOffset)
            }

            override fun onPageSelected(position: Int) {
            }
        })

    }

    var rectIndicator = RectF()//記錄下要畫的線條的left和right位置
    fun updateIndicator(position: Int, positionOffset: Float) {
    if(position>=tabCount){
            return
        }
        var rectF = getTextViewRect(position)
        var rectF2 = rectF
        if (position < tabCount - 1) {
            rectF2 = getTextViewRect(position + 1)
        }
        if (positionOffset < 0.5) {
            rectIndicator.left = rectF.left + rectF.width * positionOffset //第一個最左邊移動到第一個的中心位置
            rectIndicator.right = rectF.right + (rectF2.center - rectF.right) * positionOffset * 2 //移動范圍,從第一個右邊,移動到另一個控件的中心位置
        } else {
            rectIndicator.left = rectF2.left - (rectF2.left - rectF.center) * (1 - positionOffset) * 2 //移動范圍,從第一個中心到另一個最左邊
            rectIndicator.right = rectF2.left + rectF2.width * positionOffset//第二個中心點到第二個的右邊
        }
        ViewCompat.postInvalidateOnAnimation(this@TabLayoutFixedFill)
    }

    /**找出某個tabview里Textview的left和right位置*/
    private fun getTextViewRect(selectedPosition: Int): ViewOption {
        var slidingTabStrip = getChildAt(0) as LinearLayout
        var tabView = slidingTabStrip.getChildAt(selectedPosition) as LinearLayout
        var textView = tabView.getChildAt(1);
        val add = (factor - 1) * textView.width / 2
        return ViewOption(tabView.left + textView.left - add, tabView.left + textView.right + add)
    }

    /**記錄下view的left,right,center ,and  width*/
    data class ViewOption(var left: Float, var right: Float, var center: Float = (right + left) / 2f, var width: Float = (right - left))
}

如果有人說我沒有綁定viewpager咋辦,也很簡單,我上邊的updateIndicator方法,你可以在切換tab的時候調用這個方法也可以。或者你也可以直接用最老的那種方法,就是畫條線的那個也可以。

帶背景的

上邊介紹的是畫了一條線,其實畫啥都行,只要你愿意。
看下這種效果,就是在上邊的代碼上稍微修改下線條的高度,弄個圓角就可以了


20181119_134552.gif

布局如下
設置下左右的padding,完事設置下高度。padding是高度的一半,為了實現兩邊半圓的效果,這樣弄最簡單。
不想設置高度,你自己在里邊算下文本的高度,然后自己算下padding也隨你了,

    <com.charliesong.demo0327.pathanim.TabLayoutFixedWrap
        android:id="@+id/tabfixed"
        app:tabPaddingStart="20dp"
        app:tabPaddingEnd="20dp"
        android:layout_width="wrap_content"
        android:layout_height="40dp"/>

代碼如下
增加了2個參數 var tabPaddingStart=0
var tabPaddingEnd=0;其實正常這兩個是一樣的,要不圓角就不一樣拉。
然后onDraw里畫個帶圓角的
canvas.drawRoundRect(rect,tabPaddingStart/1f,height/2f, paintLine)

import android.content.Context
import android.graphics.Canvas
import android.support.design.widget.TabLayout
import android.support.v4.view.ViewPager
import android.util.AttributeSet
import android.graphics.Color
import android.graphics.Paint
import android.widget.LinearLayout
import android.graphics.RectF
import android.support.design.R
import android.support.v4.view.ViewCompat

class TabLayoutFixedWrap : TabLayout {
    constructor(context: Context) : this(context, null)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
        initAttrs(context,attrs,defStyleAttr)
    }

    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs,R.attr.tabStyle)

    private fun initAttrs(context: Context, attrs: AttributeSet?,defStyleAttr: Int) {
        val a = context.obtainStyledAttributes(attrs, R.styleable.TabLayout,
                defStyleAttr, R.style.Widget_Design_TabLayout)
        paintLine.color = a.getColor(R.styleable.TabLayout_tabIndicatorColor, 0)
        val padding = a.getDimensionPixelSize(R.styleable.TabLayout_tabPadding, 0)
        tabPaddingStart = a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingStart,padding)
        tabPaddingEnd = a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingEnd,padding)
        a.recycle()
        setSelectedTabIndicatorColor(Color.TRANSPARENT)
    }
    var tabPaddingStart=0
    var tabPaddingEnd=0;
    var factor = 1f//這里沒啥用了
    var paintLine = Paint()
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val rect=RectF(rectIndicator.left-tabPaddingStart, 0f, rectIndicator.right+tabPaddingEnd, getHeight().toFloat())
        canvas.drawRoundRect(rect,tabPaddingStart/1f,height/2f, paintLine)
    }

    override fun setupWithViewPager(viewPager: ViewPager?, autoRefresh: Boolean) {
        super.setupWithViewPager(viewPager, autoRefresh)
        viewPager?.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
            override fun onPageScrollStateChanged(state: Int) {
            }

            override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
                updateIndicator(position, positionOffset)
            }

            override fun onPageSelected(position: Int) {
            }
        })

    }

    var rectIndicator = RectF() //記錄下要畫的線條的left和right位置

     fun updateIndicator(position: Int, positionOffset: Float) {
        if(position>=tabCount){
            return
        }
        var rectF = getTextViewRect(position)
        var rectF2 = rectF
        if (position < tabCount - 1) {
            rectF2 = getTextViewRect(position + 1)
        }
        if (positionOffset < 0.5) {
            rectIndicator.left = rectF.left + rectF.width * positionOffset //第一個最左邊移動到第一個的中心位置
            rectIndicator.right = rectF.right + (rectF2.center - rectF.right) * positionOffset * 2 //移動范圍,從第一個右邊,移動到另一個控件的中心位置
        } else {
            rectIndicator.left = rectF2.left - (rectF2.left - rectF.center) * (1 - positionOffset) * 2 //移動范圍,從第一個中心到另一個最左邊
            rectIndicator.right = rectF2.left + rectF2.width * positionOffset//第二個中心點到第二個的右邊
        }
        ViewCompat.postInvalidateOnAnimation(this@TabLayoutFixedWrap)
    }

    /**找出某個tabview里Textview的left和right位置*/
    private fun getTextViewRect(selectedPosition: Int): ViewOption {
        var slidingTabStrip = getChildAt(0) as LinearLayout
        var tabView = slidingTabStrip.getChildAt(selectedPosition) as LinearLayout
        var textView = tabView.getChildAt(1);
        val add = (factor - 1) * textView.width / 2
        return ViewOption(tabView.left + textView.left - add, tabView.left + textView.right + add)
    }

    /**記錄下view的left,right,center ,and  width*/
    data class ViewOption(var left: Float, var right: Float, var center: Float = (right + left) / 2f, var width: Float = (right - left))
}

如果你需要的是那種scrollable的效果,那么添加如下的屬性即可
系統默認tabview有個最小寬度的,你不設置的話,可能看到文字很少的tab寬度也很大。

        app:tabMode="scrollable"
        app:tabMinWidth="2dp"

其他一些看源碼的收獲

如果我們不設置tablayout的高度的話,用個warp,那么他的高度其實是固定的。
圖片文字同時存在,是72dp,只有文字的話48dp
看下系統的一些默認值
tab是有最大寬度一說的,而且scroll模式下默認有個最小寬度的design_tab_scrollable_min_width

    <style name="Base.Widget.Design.TabLayout" parent="android:Widget">
        <item name="tabMaxWidth">@dimen/design_tab_max_width</item>
        <item name="tabIndicatorColor">?attr/colorAccent</item>
        <item name="tabIndicatorHeight">2dp</item>
        <item name="tabPaddingStart">12dp</item>
        <item name="tabPaddingEnd">12dp</item>
        <item name="tabBackground">?attr/selectableItemBackground</item>
        <item name="tabTextAppearance">@style/TextAppearance.Design.Tab</item>
        <item name="tabSelectedTextColor">?android:textColorPrimary</item>
    </style>
    <dimen name="design_tab_max_width">264dp</dimen>
    <dimen name="design_tab_scrollable_min_width">72dp</dimen>
    <dimen name="design_tab_text_size">14sp</dimen>
    <dimen name="design_tab_text_size_2line">12sp</dimen>

    <style name="Widget.Design.TabLayout" parent="Base.Widget.Design.TabLayout">
        <item name="tabGravity">fill</item>
        <item name="tabMode">fixed</item>
    </style>

如果是pad的話,values-sw600dp目錄默認如下

<dimen name="design_tab_scrollable_min_width">160dp</dimen>
    <style name="Widget.Design.TabLayout" parent="Base.Widget.Design.TabLayout">
        <item name="tabGravity">center</item>
        <item name="tabMode">fixed</item>
    </style>

可以看到,手機默認是fill,而平板默認是center,所以如果不設置tabGravity,平板下你會發現tab不是平分寬度的,而是居中顯示的。

補充

除了比較復雜的需求,如果只是要求修改選中的文字的效果,比如加粗,字體方法這些,還是可以簡單實現的,還是那句話,tablayout的整體布局結構開頭也都說了,那么拿到tab也就拿到了position,有了position自然能拿到那個textview控件了。

        tab_page.addOnTabSelectedListener(object :TabLayout.OnTabSelectedListener{
            override fun onTabReselected(tab: TabLayout.Tab?) {

            }

            override fun onTabUnselected(tab: TabLayout.Tab) {
                changeTextStyle(tab.position,false)
            }

            override fun onTabSelected(tab: TabLayout.Tab) {
                changeTextStyle(tab.position,true)
            }
        })

    private fun changeTextStyle(position: Int,selected:Boolean){
        var parent=tab_page.getChildAt(0) as LinearLayout
        var tabview=parent.getChildAt(position) as LinearLayout
       //tabview也可以通過反射tab的mView這個字段來獲取
        var tv=tabview.getChildAt(1) as TextView
        tv.setTypeface(if(selected) Typeface.DEFAULT_BOLD else Typeface.DEFAULT)
        tv.setTextSize(if(selected) 40f else 15f)
    }

問題

需求是2個tab平分顯示,可在平板上看到2個tab擠在一起了


image.png

添加如下的屬性,修改下最大值,弄大點,另外游標長度默認是和文字長度一樣的,下邊的true可以保證和tab一樣寬

app:tabIndicatorFullWidth="true"
        app:tabMaxWidth="2000dp"
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容