先上图片
上代码
一、BaseText去设置TabLayout文字样式
import android.content.Context
import android.view.Gravity
import android.widget.TextView
import com.google.android.material.tabs.TabLayout
open class BaseText {
protected var context: Context? = null
protected var tabLayout: TabLayout? = null
protected var normalTextBold: Boolean = false
protected var selectTextBold: Boolean = false
protected var normalTextSize: Float = 14f
protected var selectTextSize: Float = 14f
fun bindTabLayout(tabLayout: TabLayout) {
this.tabLayout = tabLayout
this.context = tabLayout.context
}
fun setNormalTextBold(normalTextBold: Boolean): BaseText {
this.normalTextBold = normalTextBold
return this
}
fun setSelectTextBold(selectTextBold: Boolean): BaseText {
this.selectTextBold = selectTextBold
return this
}
fun setNormalTextSize(normalTextSize: Float): BaseText {
this.normalTextSize = normalTextSize
return this
}
fun setSelectTextSize(selectTextSize: Float): BaseText {
this.selectTextSize = selectTextSize
return this
}
fun bind() {
tabLayout?.post {
tabLayout?.apply {
for (i in 0 until tabCount) {
getTabAt(i)?.let {
it.customView = TextView(context).apply {
text = it.text
textSize =
if (selectedTabPosition == i) selectTextSize else normalTextSize
if (selectedTabPosition == i)
paint?.isFakeBoldText = selectTextBold
else
paint?.isFakeBoldText = normalTextBold
gravity = Gravity.CENTER
setTextColor(tabTextColors)
}
}
}
addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {
(tab?.customView as? TextView)?.apply {
textSize = selectTextSize
paint?.isFakeBoldText = selectTextBold
}
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
(tab?.customView as? TextView)?.apply {
textSize = normalTextSize
paint?.isFakeBoldText = normalTextBold
}
}
override fun onTabSelected(tab: TabLayout.Tab?) {
(tab?.customView as? TextView)?.apply {
textSize = selectTextSize
paint?.isFakeBoldText = selectTextBold
}
}
})
}
}
}
}
二、设置指示器样式
1.BaseIndicator.kt 基类
import android.content.Context
import androidx.annotation.ColorInt
import androidx.annotation.Px
import com.google.android.material.tabs.TabLayout
abstract class BaseIndicator {
companion object {
//填充满
const val MATCH = -1
}
protected var width: Int = 0
protected var height: Int = 0
protected var context: Context? = null
protected var tabLayout: TabLayout? = null
fun bindTabLayout(tabLayout: TabLayout) {
this.tabLayout = tabLayout
this.context = tabLayout.context
}
fun setColor(@ColorInt color: Int): BaseIndicator {
tabLayout?.setSelectedTabIndicatorColor(color)
return this
}
fun setWidth(@Px width: Int): BaseIndicator {
this.width = width
return this
}
fun setHeight(@Px height: Int): BaseIndicator {
this.height = height
return this
}
fun setGravity(gravity: Int): BaseIndicator {
tabLayout?.setSelectedTabIndicatorGravity(gravity)
return this
}
abstract fun bind()
}
2.LinearIndicator.kt 线性指示器样式
import android.graphics.Paint
import android.graphics.drawable.LayerDrawable
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.os.Build
import android.view.Gravity
import com.google.android.material.tabs.TabLayout
import com.loper7.tab_expand.ext.toPx
open class LinearIndicator : BaseIndicator() {
private var angle: Int = 0
fun setAngle(angle: Int): LinearIndicator {
this.angle = angle
return this
}
override fun bind() {
tabLayout?.post {
val drawable = ShapeDrawable()
if (height == MATCH)
height = tabLayout?.height!!
if (angle <= 0f)
angle = if (height == 0) 100 else height / 2
val f_angle = angle.toFloat()
val outerR =
floatArrayOf(f_angle, f_angle, f_angle, f_angle, f_angle, f_angle, f_angle, f_angle)
val shape = RoundRectShape(outerR, null, null)
drawable.shape = shape
drawable.paint.style = Paint.Style.FILL
val layerDrawable = LayerDrawable(arrayOf(drawable))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
layerDrawable.setLayerHeight(0, height)
layerDrawable.setLayerWidth(0, width)
layerDrawable.setLayerGravity(0, Gravity.CENTER)
}
if (width == 0 && height == 0)
tabLayout?.setSelectedTabIndicator(drawable)
else
tabLayout?.setSelectedTabIndicator(layerDrawable)
if (height == 0)
tabLayout?.setSelectedTabIndicatorHeight(3.toPx())
else
tabLayout?.setSelectedTabIndicatorHeight(height)
//对自适应宽度进行处理
if (width <= 0 && tabLayout?.tabSelectedIndicator is LayerDrawable) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
(tabLayout?.tabSelectedIndicator as LayerDrawable).setLayerWidth(
0,
tabLayout?.getTabAt(0)!!.view.width
)
}
tabLayout?.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabSelected(tab: TabLayout.Tab?) {
tab?.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
(tabLayout?.tabSelectedIndicator as LayerDrawable).setLayerWidth(
0,
tab.view.width
)
}
}
}
})
}
}
}
}
3.TriangleIndicator.kt 三角指示器样式
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.os.Build
import android.view.Gravity
import androidx.core.content.ContextCompat
import com.loper7.tab_expand.R
import com.loper7.tab_expand.ext.toPx
open class TriangleIndicator : BaseIndicator() {
private var path = Path.POSITIVE
private var drawable: Drawable? = null
fun setPath(path: Path): TriangleIndicator {
this.path = path
return this
}
override fun bind() {
tabLayout?.post {
if (height == MATCH)
height = tabLayout?.height!!
if (drawable == null) {
drawable = if (path == Path.POSITIVE) {
ContextCompat.getDrawable(context!!, R.drawable.tab_indicator_triangle_z)!!
} else {
ContextCompat.getDrawable(context!!, R.drawable.tab_indicator_triangle_f)!!
}
}
if (width == 0)
width = 12.toPx()
if (height == 0)
height = 12.toPx()
if (height == 0)
tabLayout?.setSelectedTabIndicatorHeight(3.toPx())
else
tabLayout?.setSelectedTabIndicatorHeight(height)
val layerDrawable = LayerDrawable(arrayOf(drawable))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
layerDrawable.setLayerHeight(0, height)
layerDrawable.setLayerWidth(0, width)
layerDrawable.setLayerGravity(0, Gravity.CENTER)
}
tabLayout?.setSelectedTabIndicator(layerDrawable)
}
}
enum class Path {
/**
* POSITIVE 正
* NEGATIVE 反
*/
POSITIVE,
NEGATIVE
}
}
4.CustomIndicator.kt 自定义图片指示器样式
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.os.Build
import android.view.Gravity
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.google.android.material.tabs.TabLayout
import com.loper7.tab_expand.ext.toPx
open class CustomIndicator : BaseIndicator() {
private var drawable: Drawable? = null
fun setDrawable(drawable: Drawable): CustomIndicator {
this.drawable = drawable
return this
}
fun setDrawable(@DrawableRes resId: Int): CustomIndicator {
this.drawable = ContextCompat.getDrawable(context!!, resId)
return this
}
override fun bind() {
tabLayout?.post {
if (height == MATCH)
height = tabLayout?.height!!
val layerDrawable = LayerDrawable(arrayOf(drawable))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
layerDrawable.setLayerHeight(0, height)
layerDrawable.setLayerWidth(0, width)
layerDrawable.setLayerGravity(0, Gravity.CENTER)
}
if (width == 0 && height == 0)
tabLayout?.setSelectedTabIndicator(drawable)
else
tabLayout?.setSelectedTabIndicator(layerDrawable)
if (height == 0)
tabLayout?.setSelectedTabIndicatorHeight(3.toPx())
else
tabLayout?.setSelectedTabIndicatorHeight(height)
//对自适应宽度进行处理
if (width <= 0 && tabLayout?.tabSelectedIndicator is LayerDrawable) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
(tabLayout?.tabSelectedIndicator as LayerDrawable).setLayerWidth(
0,
tabLayout?.getTabAt(0)!!.view.width
)
}
tabLayout?.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabSelected(tab: TabLayout.Tab?) {
tab?.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
(tabLayout?.tabSelectedIndicator as LayerDrawable).setLayerWidth(
0,
tab.view.width
)
}
}
}
})
}
}
}
}
三、工具类和接口
fun Int.toDp(): Int = (this / Resources.getSystem().displayMetrics.density).toInt()
fun Int.toPx(): Int = (this * Resources.getSystem().displayMetrics.density).toInt()
fun Double.toDp(): Int = (this / Resources.getSystem().displayMetrics.density).toInt()
fun Double.toPx(): Int = (this * Resources.getSystem().displayMetrics.density).toInt()
import com.google.android.material.tabs.TabLayout
import com.loper7.tab_expand.indicator.BaseIndicator
import com.loper7.tab_expand.text.BaseText
/**
* 绑定tabLayout指示器
*/
inline fun TabLayout.buildIndicator():T {
val indicator = T::class.java.newInstance()
indicator.bindTabLayout(this)
return indicator
}
/**
* 绑定tabLayout文字设置
*/
inline fun TabLayout.buildText():T {
val text = T::class.java.newInstance()
text.bindTabLayout(this)
return text
}
四、使用方式
MainActivity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.content.ContextCompat
import com.google.android.material.tabs.TabLayout
import com.loper7.tablayout_ext.adapter.MainFragmentAdapter
import com.loper7.tablayout_ext.helper.StatusBarHelper
import com.loper7.tab_expand.ext.buildIndicator
import com.loper7.tab_expand.ext.buildText
import com.loper7.tab_expand.ext.toPx
import com.loper7.tab_expand.indicator.CustomIndicator
import com.loper7.tab_expand.indicator.LinearIndicator
import com.loper7.tab_expand.text.BaseText
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_main.tabLayout
import kotlinx.android.synthetic.main.activity_main.viewPager
import kotlinx.android.synthetic.main.fragment_other_indicator.*
class MainActivity : AppCompatActivity() {
private lateinit var adapter:MainFragmentAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
StatusBarHelper.setDarkStatusIcon(this,true)
adapter = MainFragmentAdapter(supportFragmentManager)
viewPager.adapter = adapter
viewPager.offscreenPageLimit = 3
tabLayout.setupWithViewPager(viewPager)
tabLayout.buildIndicator()
.setDrawable(ContextCompat.getDrawable(this, R.mipmap.icon_indicator)!!)
.setWidth(15.toPx())
.setHeight(6.toPx())
.bind()
tabLayout.buildText()
.setNormalTextBold(true)
.setSelectTextSize(15f)
.setSelectTextBold(true).bind()
}
}
activity_main.xml
fragment
1.线性
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.fragment.app.Fragment
import com.loper7.tab_expand.ext.buildIndicator
import com.loper7.tab_expand.ext.buildText
import com.loper7.tab_expand.ext.toPx
import com.loper7.tab_expand.indicator.BaseIndicator
import com.loper7.tab_expand.indicator.LinearIndicator
import com.loper7.tab_expand.text.BaseText
import com.loper7.tablayout_ext.R
import com.loper7.tablayout_ext.adapter.SimpleFragmentAdapter
import kotlinx.android.synthetic.main.fragment_linear_indicator.*
class LinearIndicatorFragment : Fragment() {
var mRootView: View? = null
private lateinit var adapter: SimpleFragmentAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
if (mRootView == null) {
mRootView = View.inflate(
context,
R.layout.fragment_linear_indicator, null
)
}
return mRootView
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = SimpleFragmentAdapter(childFragmentManager)
viewPager.adapter = adapter
tabLayout_default.setupWithViewPager(viewPager)
tabLayout.setupWithViewPager(viewPager)
tabLayout1.setupWithViewPager(viewPager)
tabLayout2.setupWithViewPager(viewPager)
tabLayout3.setupWithViewPager(viewPager)
tabLayout4.setupWithViewPager(viewPager)
// LinearIndicator
tabLayout.buildIndicator().bind()
tabLayout.buildText()
.setNormalTextBold(false)
.setSelectTextBold(true)
.setNormalTextSize(16f)
.setSelectTextSize(18f)
.bind()
// LinearIndicator (w=35,h=3.5)
tabLayout1.buildIndicator()
.setWidth(35.toPx())
.setHeight(4.toPx())
.bind()
tabLayout1.buildText()
.setNormalTextBold(false)
.setSelectTextBold(true)
.bind()
// LinearIndicator (w=5,h=5)
tabLayout2.buildIndicator()
.setWidth(5.toPx())
.setHeight(5.toPx())
.bind()
tabLayout2.buildText()
.setNormalTextBold(false)
.setSelectTextBold(true)
.bind()
// LinearIndicator (w=auto,h=match,a=4)
tabLayout3.buildIndicator()
.setAngle(4.toPx())
.setHeight(BaseIndicator.MATCH)
.setWidth(BaseIndicator.MATCH)
.bind()
tabLayout3.buildText()
.setNormalTextBold(true)
.setSelectTextBold(true)
.bind()
// LinearIndicator (w=auto,h=22,a=auto)
tabLayout4.buildIndicator()
.setHeight(22.toPx())
.bind()
tabLayout4.buildText()
.setNormalTextBold(true)
.setSelectTextBold(true)
.bind()
tabLayout.getTabAt(1)?.orCreateBadge?.backgroundColor = Color.parseColor("#FF9900")
tabLayout.getTabAt(1)?.orCreateBadge?.number = 6
}
}
fragment_linear_indicator.xml
2.三角
package com.loper7.tablayout_ext.fragment
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.google.android.material.tabs.TabLayout
import com.loper7.tab_expand.ext.buildIndicator
import com.loper7.tab_expand.ext.toPx
import com.loper7.tab_expand.indicator.TriangleIndicator
import com.loper7.tablayout_ext.R
import com.loper7.tablayout_ext.adapter.SimpleFragmentAdapter
import kotlinx.android.synthetic.main.fragment_triangle_indicator.*
class TriangleIndicatorFragment :Fragment() {
var mRootView: View? = null
private lateinit var adapter: SimpleFragmentAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
if (mRootView == null) {
mRootView = View.inflate(context, R.layout.fragment_triangle_indicator, null)
}
return mRootView
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = SimpleFragmentAdapter(childFragmentManager)
viewPager.adapter = adapter
tabLayout.setupWithViewPager(viewPager)
tabLayout1.setupWithViewPager(viewPager)
tabLayout2.setupWithViewPager(viewPager)
// TriangleIndicator
tabLayout.buildIndicator().bind()
// TriangleIndicator(p=NEGATIVE)
tabLayout1.buildIndicator()
.setPath(TriangleIndicator.Path.NEGATIVE)
.bind()
// TriangleIndicator(w=10,h=10,p=NEGATIVE,g=top)
tabLayout2.buildIndicator()
.setPath(TriangleIndicator.Path.NEGATIVE)
.setWidth(10.toPx())
.setHeight(10.toPx())
.setColor(ContextCompat.getColor(context!!,R.color.colorAccent))
.setGravity(TabLayout.INDICATOR_GRAVITY_TOP)
.bind()
}
}
fragment_triangle_indicator.xml
3.自定义图片
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.loper7.tab_expand.ext.buildIndicator
import com.loper7.tab_expand.ext.buildText
import com.loper7.tab_expand.ext.toPx
import com.loper7.tab_expand.indicator.CustomIndicator
import com.loper7.tab_expand.text.BaseText
import com.loper7.tablayout_ext.R
import com.loper7.tablayout_ext.adapter.CustomFragmentAdapter
import kotlinx.android.synthetic.main.fragment_other_indicator.*
class CustomIndicatorFragment : Fragment() {
var mRootView: View? = null
private lateinit var adapter: CustomFragmentAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
if (mRootView == null) {
mRootView = View.inflate(context, R.layout.fragment_other_indicator, null)
}
return mRootView
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = CustomFragmentAdapter(childFragmentManager)
viewPager.adapter = adapter
tabLayout.setupWithViewPager(viewPager)
// custom1
tabLayout.buildIndicator()
.setDrawable(ContextCompat.getDrawable(context!!, R.mipmap.icon_indicator)!!)
.setWidth(15.toPx())
.setHeight(6.toPx())
.bind()
tabLayout.buildText()
.setNormalTextBold(false)
.setSelectTextBold(true)
.setNormalTextSize(16f)
.setSelectTextSize(18f)
.bind()
}
}
fragment_other_indicator.xml
adapter
import androidx.fragment.app.*
import com.loper7.tablayout_ext.fragment.LinearIndicatorFragment
import com.loper7.tablayout_ext.fragment.CustomIndicatorFragment
import com.loper7.tablayout_ext.fragment.TriangleIndicatorFragment
class MainFragmentAdapter(fm:FragmentManager) : FragmentStatePagerAdapter(fm) {
override fun getCount(): Int {
return 3
}
override fun getItem(position: Int): Fragment {
return when(position){
0->LinearIndicatorFragment()
1-> TriangleIndicatorFragment()
else->CustomIndicatorFragment()
}
}
override fun getPageTitle(position: Int): CharSequence? {
return when(position){
0-> "LINEAR"
1-> "TRIANGLE"
2-> "CUSTOM"
else->""
}
}
}
import androidx.fragment.app.*
import com.loper7.tablayout_ext.SimpleFragment
class SimpleFragmentAdapter(fm:FragmentManager) : FragmentStatePagerAdapter(fm) {
override fun getCount(): Int {
return 6
}
override fun getItem(position: Int): Fragment {
return SimpleFragment.newInstance("PAGE $position")
}
override fun getPageTitle(position: Int): CharSequence? {
return when(position){
0-> "JAVA"
1-> "OBJECT-C"
2-> "FLUTTER"
3-> "KOTLIN"
4-> "SWIFT"
5-> "REACT NATIVE"
else-> "PHP"
}
}
}
import androidx.fragment.app.*
import com.loper7.tablayout_ext.SimpleFragment
class CustomFragmentAdapter(fm:FragmentManager) : FragmentStatePagerAdapter(fm) {
override fun getCount(): Int {
return 6
}
override fun getItem(position: Int): Fragment {
return SimpleFragment.newInstance("PAGE $position")
}
override fun getPageTitle(position: Int): CharSequence? {
return when(position){
0-> "直播"
1-> "推荐"
2-> "热门"
3-> "追番"
4-> "抗击肺炎"
5-> "总之就是非常可爱"
else-> "PHP"
}
}
}
SimpleFragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_simple.*
class SimpleFragment :Fragment() {
var mRootView: View? = null
companion object {
fun newInstance(text: String): SimpleFragment {
val args = Bundle()
args.putString("text", text)
val fragment = SimpleFragment()
fragment.arguments = args
return fragment
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
if (mRootView == null) {
mRootView = View.inflate(context, R.layout.fragment_simple, null)
}
return mRootView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
tv_text.text = requireArguments().getString("text")
}
}
fragment_simple.xml
![ic_indicator_fire.png](https://upload-images.jianshu.io/upload_images/22679253-7728493deed59ee9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![ic_indicator_index.png](https://upload-images.jianshu.io/upload_images/22679253-6efbee0bf5bb76dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![ic_indicator_t.png](https://upload-images.jianshu.io/upload_images/22679253-803f822d21b4b94f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![icon_indicator.png](https://upload-images.jianshu.io/upload_images/22679253-a065cf65234f25e9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![ic_indicator_finger.png](https://upload-images.jianshu.io/upload_images/22679253-923e14a7fccbed88.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
其他
tab_indicator_triangle_f.xml
tab_indicator_triangle_z.xml
最后附上GitHub地址:https://github.com/loperSeven/tablayout-ext