一、实现效果

二、引入依赖

appbuild.gradle在添加以下代码
1、TabLayoutimplementation 'com.google.android.material:material:1.1.0'
2、implementation 'com.github.li-xiaojun:StateLayout:1.3.4' //allprojects {…增加:maven { url ‘https://jitpack.io’ }…}
3、implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6',这个里面带的适配器,直接调用就即可
这依赖包还需要得到要添加,在Projectbuild.gradle在添加以下代码,不添加就不行

allprojects {
    repositories {
        ...
        maven { url "https://jitpack.io" }//加上
    }
}

三、源码实现

1、ViewPager实体类

PageInfo.java

package com.example.myapplication3.bean;

import com.example.myapplication3.fragment.BaseFragment;

public class PageInfo {

//    public String title;
    public BaseFragment fragment;

//    public PageInfo(String title, BaseFragment fragment) {
//        this.title = title;
//        this.fragment = fragment;
//    }

    public PageInfo(BaseFragment fragment) {
        this.fragment = fragment;
    }
}

ViewPager两个页面,TestFragment1.ktTestFragment2.tk的代码一样,布局也一样,自己写就即可
TestFragment1.kt

package com.example.myapplication3.fragment

import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.myapplication3.R
import com.example.myapplication3.adapter.RvAdapter
import kotlinx.android.synthetic.main.testfragment1.recyclerView

class TestFragment1 : BaseFragment(){

    private val mAdapter by lazy {
        RvAdapter().apply {
//            setOnItemLongClickListener(activity)
        }
    }

    override val layoutId: Int = R.layout.testfragment1
    override fun init(view: View?) {
        val itemList: MutableList<String> = ArrayList()
        for (i in 0..2) {
            itemList.add("position $i")
        }
        val layoutManager = LinearLayoutManager(activity)
        layoutManager.orientation = LinearLayoutManager.HORIZONTAL
        recyclerView.layoutManager = layoutManager
        recyclerView.adapter = mAdapter
        mAdapter.setList(itemList)
    }
}

testfragment1.kt

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</RelativeLayout>

列表适配器RvAdapter.kt

package com.example.myapplication3.adapter

import android.widget.TextView
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.myapplication3.R

class RvAdapter(layoutResId: Int = R.layout.rv_item) : BaseQuickAdapter<String, BaseViewHolder>(layoutResId) {

    override fun convert(holder: BaseViewHolder, item: String) {
        val itemTv = holder.getView<TextView>(R.id.item_tv)
        itemTv.text = item
    }
}

rv_item.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_width="112dp"
    android:layout_height="112dp"
    android:foreground="?android:attr/selectableItemBackground"
    card_view:cardBackgroundColor="@color/light_gray"
    card_view:cardCornerRadius="20dp"
    card_view:cardElevation="2dp"
    card_view:cardUseCompatPadding="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/iv"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_gravity="center"
            android:src="@mipmap/ic_c" />

        <TextView
            android:id="@+id/item_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="测试"
            android:textSize="14dp"/>
    </LinearLayout>
</androidx.cardview.widget.CardView>

colors.xml中添加的颜色

	<color name="black">#000000</color><!--  黑色  -->
    <color name="white">#FFFFFFFF</color><!--  白色  -->
    <color name="gray">#959595</color><!--  灰色  -->
    <color name="light_gray">#E7E7E7</color><!--  浅灰  -->
    <color name="red">#FF0000</color><!--  红色  -->
    <color name="yellow">#FFC107</color><!--  黄色  -->
    <color name="purple">#FFBB86FC</color><!--  紫色  -->

这两个页面代码要继承父类BaseFragment()BaseFragment.kt

package com.example.myapplication3.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.lxj.statelayout.StateLayout

abstract class BaseFragment : Fragment() {
    var vieww: View? = null
    var isInit = false
    var stateLayout: StateLayout? = null
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        if (vieww == null) {
            vieww = inflater.inflate(layoutId, container, false)
            stateLayout = StateLayout(requireContext()).wrap(vieww).showLoading()
        }
        return stateLayout
    }

    override fun onResume() {
        super.onResume()
        safeInit()
    }

    private fun safeInit() {
        if (userVisibleHint && vieww != null) {
            if (!isInit) {
                isInit = true
                init(vieww)
                stateLayout!!.postDelayed({ stateLayout!!.showContent() }, 300)
            }
        }
    }

    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        safeInit()
    }

    protected abstract val layoutId: Int
    abstract fun init(view: View?)
    fun toast(msg: String?) {
//        Toast.makeText(XPopupApp.context, msg, Toast.LENGTH_SHORT).show();
    }
}

2、指示器样式(自定义类)

自定义ViewPagerIndicator.kt

package com.example.myapplication3.view

import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.widget.FrameLayout
import androidx.annotation.Nullable
import androidx.viewpager.widget.ViewPager
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import com.example.myapplication3.R

class ViewPagerIndicator @JvmOverloads constructor(
    context: Context,
    @Nullable attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) :
    FrameLayout(context, attrs, defStyleAttr) {
//    private val rootView: View
    private val mRootView: View
    private val indView: View
    var indViewWidth = 0

    init {
        val root = inflate(context, R.layout.app_viewpager_indicator, this)
        mRootView = root.findViewById<View>(R.id.root)
        indView = root.findViewById<View>(R.id.ind_view)
    }

    override fun draw(canvas: Canvas) {
        super.draw(canvas)
    }

    fun setWithViewPager(viewPager: ViewPager) {
        //如果没有adapter,则隐藏不显示
        if (null == viewPager.adapter) {
            visibility = GONE
            Log.e(javaClass.simpleName, "no adapter")
            return
        }
        //获取viewPager中fragment的数量
        val count = viewPager.adapter!!.count
        if (count == 0) {
            return
        }

        //加载到window之后再进行view宽度的获取
        mRootView.post(Runnable { //获取当前滑块的宽度
            indViewWidth = width / count
            val layoutParams = indView.layoutParams as LayoutParams
            layoutParams.width = indViewWidth
            indView.layoutParams = layoutParams
        })
        viewPager.addOnPageChangeListener(object : OnPageChangeListener {
            /**
             *
             * @param position
             * @param positionOffset [0,1]中的值,指示在位置处与页面的偏移百分比。
             * @param positionOffsetPixels 以像素为单位的值,表示与位置的偏移量。
             */
            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int
            ) {
                //获取滑块距父布局左侧的距离
                val left = (position * indViewWidth + positionOffset * indViewWidth).toInt()

                //重新布局滑块view
                indView.layout(left, indView.top, left + indViewWidth, indView.bottom)
            }

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

指示器布局app_viewpager_indicator.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/shape_indicator_radius_gray">

    <View
        android:id="@+id/ind_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_indicator_radius_yellow"/>
</FrameLayout>

指示器背景灰色shape_indicator_radius_gray.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/gray" />
    <corners android:radius="50dp" />
</shape>

指示器黄色shape_indicator_radius_yellow.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/yellow" />
    <corners android:radius="50dp" />
</shape>

3、主视图实现

MainActivity.kt

package com.example.myapplication3

import android.graphics.Typeface
import android.os.Bundle
import android.util.Log
import android.util.TypedValue
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import com.example.myapplication3.bean.PageInfo
import com.example.myapplication3.fragment.TestFragment1
import com.example.myapplication3.fragment.TestFragment2
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import kotlinx.android.synthetic.main.activity_main.indicator
import kotlinx.android.synthetic.main.activity_main.tablayout
import kotlinx.android.synthetic.main.activity_main.viewPager

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        init()
    }

    private fun init() {

        //TabLayout添加自定义分割线并且可以修改分割线高度
        val linearLayout = tablayout.getChildAt(0) as LinearLayout
        linearLayout.showDividers = LinearLayout.SHOW_DIVIDER_MIDDLE
        linearLayout.dividerDrawable = ContextCompat.getDrawable(this, R.drawable.layout_divider_vertical)
//        linearLayout.dividerPadding = 50
        linearLayout.dividerPadding = 23

        viewPager.adapter = MainAdapter(supportFragmentManager)
        viewPager.currentItem = 0 //当前值设置为1才能仅显示一个默认视图
        tablayout.setupWithViewPager(viewPager)

        //****新代码**
        tablayout.getTabAt(0)?.setCustomView(R.layout.text)
        val toMyTextView1 = tablayout.getTabAt(0)?.customView?.findViewById<TextView>(R.id.textView)
        toMyTextView1?.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
        toMyTextView1?.textSize = 15F
        toMyTextView1?.setTextColor(resources.getColor(R.color.black))
        toMyTextView1?.text = "热销好货"

        tablayout.getTabAt(1)?.setCustomView(R.layout.text)
        val toMyTextView2 = tablayout.getTabAt(1)?.customView?.findViewById<TextView>(R.id.textView)
        toMyTextView2?.textSize = 12F
        toMyTextView2?.setTextColor(resources.getColor(R.color.gray))
        toMyTextView2?.text = "图文直播"
        //****

        indicator.setWithViewPager(viewPager)

        tablayout.addOnTabSelectedListener(object : OnTabSelectedListener {
            override fun onTabSelected(tab: TabLayout.Tab?) {
                tab?.customView?.findViewById<TextView>(R.id.textView)?.isSelected  = true
                val tv = tab?.customView?.findViewById<TextView>(R.id.textView)
                tv?.typeface = Typeface.defaultFromStyle(Typeface.BOLD)//加粗
                tv?.textSize = 15F//直接用setTextSize(15F)也一样
                tv?.setTextColor(resources.getColor(R.color.black))
            }

            override fun onTabUnselected(tab: TabLayout.Tab?) {
                tab?.customView?.findViewById<TextView>(R.id.textView)?.isSelected = false
                val tv = tab?.customView?.findViewById<TextView>(R.id.textView)
                tv?.textSize = 12F
                tv?.setTextColor(resources.getColor(R.color.gray))
            }

            override fun onTabReselected(tab: TabLayout.Tab?) {
                Log.i("Tag","onTabReselected = ${tab?.position}")
            }
        })
    }

    class MainAdapter(fm: FragmentManager?) : FragmentPagerAdapter(fm!!) {

        private val pageInfos = arrayOf(
            PageInfo(TestFragment1()),
            PageInfo(TestFragment2()),
        )

        override fun getItem(i: Int): Fragment {
            return pageInfos[i].fragment
        }

        override fun getCount(): Int {
            return pageInfos.size
        }

//        override fun getPageTitle(position: Int): CharSequence? {
//            return pageInfos[position].title
//        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_margin="10dp"
    android:background="@drawable/shape_indicator_radius_white"
    android:padding="10dp">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/bar"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/white"
        app:elevation="0dp">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="50dp">

            <com.google.android.material.tabs.TabLayout
                android:id="@+id/tablayout"
                android:layout_width="wrap_content"
                android:layout_height="25dp"
                android:layout_alignParentLeft="true"
                android:layout_centerInParent="true"
                android:overScrollMode="never"
                app:tabContentStart="10dp"
                app:tabIndicator="@drawable/tab_indicator"
                app:tabIndicatorColor="@color/yellow"
                app:tabMode="scrollable"
                app:tabRippleColor="@android:color/transparent"
                app:tabSelectedTextColor="@color/black"
                app:tabTextColor="@color/gray">

                <com.google.android.material.tabs.TabItem
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="热销好货" />

                <com.google.android.material.tabs.TabItem
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="图文直播" />

            </com.google.android.material.tabs.TabLayout>

            <!--  app:tabBackground="@color/yellow"
                  app:tabTextAppearance="@style/TabLayoutTextStyle"-->

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerInParent="true"
                android:text="更多 >" />
        </RelativeLayout>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="112dp"
        android:layout_below="@id/bar" />

    <com.example.myapplication3.view.ViewPagerIndicator
        android:id="@+id/indicator"
        android:layout_width="40dp"
        android:layout_height="5dp"
        android:layout_below="@id/viewPager"
        android:layout_centerInParent="true" />
</RelativeLayout>

布局圆角shape_indicator_radius_white.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/white" />
    <corners android:radius="10dp" />
</shape>

TabLayout下的下划线样式tab_indicator.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:width="20dp"
        android:height="2dp"
        android:gravity="center">
        <shape>
            <corners android:radius="1dp" />
        </shape>
    </item>
</layer-list>
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐