TabLayout修改

文章目錄

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

  1. 最早實現(xiàn)臼疫,就是在tab切換的時候在下邊畫一條線
  2. 不畫線了秘噪,因為看源碼知道線條寬度和tabview一樣的厦酬,所以反射修改TabView的寬度
  3. viewPager?.addOnPageChangeListener 根據(jù)offset迈勋,動態(tài)計算view當(dāng)前的位置炬灭,線條應(yīng)該偏移的位置。
  4. 進化后靡菇,想畫啥畫啥担败,不一定是線條,反正位置都算出來了镰官。

結(jié)構(gòu)分析

QQ截圖20171026091245.png

TabLayout這個導(dǎo)航控件提前,父類關(guān)系如下
public class TabLayout extends HorizontalScrollView
public class HorizontalScrollView extends FrameLayout
里邊子空間的類型
class TabView extends LinearLayout implements OnLongClickListener
private class SlidingTabStrip extends LinearLayout
tablayout的結(jié)構(gòu)圖

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如下,根據(jù)mode和gravity設(shè)置為比重為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泳唠,最上邊也說了也是個線性布局狈网,垂直布局的,簡單看下笨腥,默認(rèn)的布局拓哺,里邊添加了一個圖片和一個TextView,自定義的就不說了脖母。添加自定義的也就是把這兩個默認(rèn)的隱藏士鸥,完事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);
            }

說了半天貌似和線條都沒關(guān)系,好吧谆级,再看下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這種鲤脏,你要求文字和線條寬度一樣们颜,那么設(shè)置如下屬性基本都能滿足需求的

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

簡單分析下,一些默認(rèn)屬性

mMode = a.getInt(R.styleable.TabLayout_tabMode, MODE_FIXED);
mTabGravity = a.getInt(R.styleable.TabLayout_tabGravity, GRAVITY_FILL);//橫屏的時候默認(rèn)style里這個是center
        final Resources res = getResources();
        mScrollableTabMinWidth = res.getDimensionPixelSize(R.dimen.design_tab_scrollable_min_width);
  //添加tabview的時候會setminwidth的猎醇,就是調(diào)用如下方法獲取最小寬度
  //可以看到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;
    }

老的做法和思路

最早比較笨的想法硫嘶,既然你這線條是畫出來了波岛,那我也畫一個好了,不過因為那線條左右邊界是動態(tài)的音半,想著麻煩则拷,就弄個固定的好了,也就是tab切換的時候才改變線條曹鸠,少了滑動效果煌茬。
我們的需求是線條和文字寬度差不多,那第一步肯定是獲取到文字的寬度了彻桃,文字的寬度哪來的坛善,當(dāng)然是獲取到tabView里的那個TextView的寬度了。

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

QQ截圖20171025170903.png

看下Tab里的那個mView就是我們要的TabView,里邊就包含有TextView
下邊就是重寫TabLayout肆饶,給他畫條線蚯妇,缺點就是線不能滑動候学,我們通過監(jiān)聽tab選中狀態(tài)的改變髓绽,來invalidate這個布局刷新線條撒穷。另外因為有了自己的線條了,所以需要把TabLayout的線條高度設(shè)置為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();
        }
        //根據(jù)整體控件的結(jié)構(gòu)冯乘,我們也能拿到那個textView
//        int selectedPosition=getSelectedTabPosition();
//        LinearLayout slidingTabStrip=(LinearLayout)getChildAt(0);
//        LinearLayout tabView= (LinearLayout) slidingTabStrip.getChildAt(selectedPosition);
//        View textView=tabView.getChildAt(1);
    }

新的做法和思路

SlidingTabStrip里有下邊的代碼是來計算線條左右邊距的洽胶,根據(jù)viewpager的偏移量動態(tài)改變
left 和right就是對應(yīng)的線條的左右點位置

 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有關(guān),那么我們改變tabView的大小即可裆馒,默認(rèn)的tabView的大小就是平分TabLayout的姊氓。
這里再強調(diào)下丐怯,我們的這個自定義只支持下邊的屬性,默認(rèn)的就是這兩個

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設(shè)計的都是線條和文字寬度一樣订雾。如果不要求滾動的時候線條動畫肢预,我還是喜歡老的那種,直接畫條線洼哎,也不影響點擊范圍烫映。

最后的實現(xiàn)

以前懶得寫啊,最近閑了噩峦,就抽空把這個實現(xiàn)吧
先看下效果圖


image.png

移動到一半效果如下圖


image.png

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

移動完成
image.png

簡單說下思路:

隱藏掉原生畫的線條【把顏色設(shè)置為透明,或者你把高度弄為0也可以】
然后給viewpager添加監(jiān)聽滑動的偏移量识补,我們來計算線條的位置
偏移量在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屬性默認(rèn)高度沒有了蝙斜,它是通過一張默認(rèn)圖片獲取的高度
所以老的代碼,給個默認(rèn)值,或者xml必須設(shè)置一個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的時候調(diào)用這個方法也可以「蟀或者你也可以直接用最老的那種方法困檩,就是畫條線的那個也可以祠挫。

帶背景的

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


20181119_134552.gif

布局如下
設(shè)置下左右的padding慌植,完事設(shè)置下高度。padding是高度的一半义郑,為了實現(xiàn)兩邊半圓的效果蝶柿,這樣弄最簡單。
不想設(shè)置高度非驮,你自己在里邊算下文本的高度交汤,然后自己算下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個參數(shù) 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的效果,那么添加如下的屬性即可
系統(tǒng)默認(rèn)tabview有個最小寬度的栋盹,你不設(shè)置的話施逾,可能看到文字很少的tab寬度也很大。

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

其他一些看源碼的收獲

如果我們不設(shè)置tablayout的高度的話例获,用個warp汉额,那么他的高度其實是固定的。
圖片文字同時存在榨汤,是72dp蠕搜,只有文字的話48dp
看下系統(tǒng)的一些默認(rèn)值
tab是有最大寬度一說的,而且scroll模式下默認(rèn)有個最小寬度的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目錄默認(rèn)如下

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

可以看到妓灌,手機默認(rèn)是fill,而平板默認(rèn)是center蜜宪,所以如果不設(shè)置tabGravity虫埂,平板下你會發(fā)現(xiàn)tab不是平分寬度的,而是居中顯示的圃验。

補充

除了比較復(fù)雜的需求掉伏,如果只是要求修改選中的文字的效果,比如加粗,字體方法這些斧散,還是可以簡單實現(xiàn)的,還是那句話供常,tablayout的整體布局結(jié)構(gòu)開頭也都說了,那么拿到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

添加如下的屬性,修改下最大值,弄大點箍镜,另外游標(biāo)長度默認(rèn)是和文字長度一樣的源祈,下邊的true可以保證和tab一樣寬

app:tabIndicatorFullWidth="true"
        app:tabMaxWidth="2000dp"
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鹿寨,隨后出現(xiàn)的幾起案子新博,更是在濱河造成了極大的恐慌薪夕,老刑警劉巖脚草,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異原献,居然都是意外死亡馏慨,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門姑隅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來写隶,“玉大人,你說我怎么就攤上這事讲仰∧脚浚” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵鄙陡,是天一觀的道長冕房。 經(jīng)常有香客問我,道長趁矾,這世上最難降的妖魔是什么耙册? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮毫捣,結(jié)果婚禮上详拙,老公的妹妹穿的比我還像新娘。我一直安慰自己蔓同,他們只是感情好饶辙,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著斑粱,像睡著了一般弃揽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天蹋宦,我揣著相機與錄音披粟,去河邊找鬼。 笑死冷冗,一個胖子當(dāng)著我的面吹牛守屉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蒿辙,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼拇泛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了思灌?” 一聲冷哼從身側(cè)響起俺叭,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎泰偿,沒想到半個月后熄守,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡耗跛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年裕照,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片调塌。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡晋南,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出羔砾,到底是詐尸還是另有隱情负间,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布姜凄,位于F島的核電站政溃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏檀葛。R本人自食惡果不足惜玩祟,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望屿聋。 院中可真熱鬧空扎,春花似錦、人聲如沸润讥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽楚殿。三九已至撮慨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背砌溺。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工影涉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人规伐。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓蟹倾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親猖闪。 傳聞我的和親對象是個殘疾皇子鲜棠,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容