一、实现效果

指示器样式,第二个gif是用模拟器的,gif有小问题,第三个截图没问题

二、引入依赖

在app的build.gradle在添加以下代码
1、implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6',这个里面带的适配器,直接调用就即可
这依赖包还需要得到要添加,在Project的build.gradle在添加以下代码,不添加就不行

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

三、源码实现

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

自定义RecyclerViewIndicator.kt

package com.example.myapplication3.view

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import androidx.annotation.Nullable
import androidx.recyclerview.widget.RecyclerView
import com.example.myapplication3.R

class RecyclerViewIndicator @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
    var indViewHeight = 0
    var rate = 0f

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

    /**
     * 绑定recyclerView
     * @param recyclerView
     * @param orientation 排列方向
     *
     * 这里用到的recyclerView的三个方法
     * computeHorizontalScrollExtent/computeVerticalScrollExtent 当前显示在屏幕上的总长度
     * computeHorizontalScrollOffset/computeVerticalScrollOffset 当前滑动的总长度
     * computeHorizontalScrollRange/computeVerticalScrollRange recylerView内部的总长度
     */
    fun setWithRecyclerView(recyclerView: RecyclerView, orientation: Int) {
        val isHorizontal = orientation == RecyclerView.HORIZONTAL
        mRootView.post(Runnable {
            val scrollRange =
                (if (isHorizontal) recyclerView.computeHorizontalScrollRange() else recyclerView.computeVerticalScrollRange()).toFloat()
            val scrollExtent =
                (if (isHorizontal) recyclerView.computeHorizontalScrollExtent() else recyclerView.computeVerticalScrollExtent()).toFloat()
            val layoutParams = indView.layoutParams as LayoutParams
            if (isHorizontal) {
                //算出比例
                rate = width.toFloat() / scrollRange
                //由显示在屏幕上的总长度算出滑块长度
                indViewWidth = (scrollExtent * rate).toInt()
                layoutParams.height = LayoutParams.MATCH_PARENT
                layoutParams.width = indViewWidth
            } else {
                rate = height.toFloat() / scrollRange
                layoutParams.width = LayoutParams.MATCH_PARENT
                indViewHeight = (scrollExtent * rate).toInt()
                layoutParams.height = indViewHeight
            }
            indView.layoutParams = layoutParams
        })
        recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                val scrollOffset =
                    if (isHorizontal) recyclerView.computeHorizontalScrollOffset() else recyclerView.computeVerticalScrollOffset()
                //由recyclerView滑动距离算出滑块移动距咯
                if (isHorizontal) {
                    val left = (scrollOffset * rate).toInt()
                    indView.layout(left, indView.top, left + indViewWidth, indView.bottom)
                } else {
                    val top = (scrollOffset * rate).toInt()
                    indView.layout(indView.left, top, indView.right, top + indViewHeight)
                }
            }
        })
    }
}

指示器布局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>

colors.xml中添加的颜色

<color name="gray">#959595</color><!--  灰色  -->
<color name="orange">#F94E18</color><!--  桔色  -->
<color name="translucent_red">#20EA5A5A</color> <!--  半透明红  -->

指示器桔色shape_indicator_radius_orange.xml

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

2、RecyclerView适配器

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"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/xx"
    android:layout_width="70dp"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_c" />

    <TextView
        android:id="@+id/item_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="测试"/>
</LinearLayout>

在这里插入图片描述

3、主视图实现

MainActivity.kt

package com.example.myapplication3

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.myapplication3.adapter.RvAdapter
import kotlinx.android.synthetic.main.activity_main.indicator
import kotlinx.android.synthetic.main.activity_main.recyclerView

class MainActivity : AppCompatActivity() {

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

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

    private fun init() {

        val itemList: MutableList<String> = ArrayList()
        for (i in 0..12) {
            itemList.add("测试$i")
        }
        val layoutManager = LinearLayoutManager(this@MainActivity)
        layoutManager.orientation = LinearLayoutManager.HORIZONTAL
        recyclerView.layoutManager = layoutManager
        recyclerView.adapter = mAdapter
        mAdapter.setList(itemList)
        indicator.setWithRecyclerView(recyclerView,LinearLayoutManager.HORIZONTAL)
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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:orientation="vertical"
    android:padding="10dp">

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="15dp"
        android:gravity="center">

        <com.example.myapplication3.view.RecyclerViewIndicator
            android:id="@+id/indicator"
            android:layout_width="55dp"
            android:layout_height="4dp" />
    </LinearLayout>
</LinearLayout>

在这里插入图片描述
布局圆角样式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/translucent_red"/>
    <corners android:radius="10dp" />
</shape>

更多推荐