Android进阶之路 - RecyclerView停止滑动后Item自动居中(SnapHelper辅助类)

发布于:2024-02-29 ⋅ 阅读:(201) ⋅ 点赞:(0)

之前一直没注意 SnapHelper 辅助类的功能,去年的时候看到项目中仅通过俩行代码设置 RecyclerView 后就提升了用户体验,觉得还是很有必要了解一下,尝试过后才发现其 PagerSnapHelperLinearSnapHelper 子类可以作用于不同场景,且听吾言

RecyclerView基础

RecyclerView扩展

RecyclerView相关功能

他字字未提喜欢你,你句句都是我愿意

你在开发项目中遇到过这样的场景吗?

HintRecyclerView 为水平滑动 && 子ItemView 宽度非 match_parent(支持同屏展示多个ItemView

  • 用户滑动列表时产生类似 ViewPager 效果,停止滑动后ItemView 自动居中(一般正常速度滑动只滑动一条数据,但是当滑动速度加快(比较费力时),可能会滑动多条数据
  • 用户正常速度滑动列表时可更轻易的滑动多条数据,停止滑动后子ItemView自动居中

Look效果:如果以下效果不能完全满足,也可以自定义SnapHelper,然后参考其子类实现增添部分你需要的业务功能,例如修改滑动速度等

请添加图片描述

Tip:核心方法仅有俩行,如急于开发,亦可直接使用或直接看实践检验,等有时间再来一同了解

创建对应的 SnapHelper 后通过 attachToRecyclerView 关联 RecyclerView 即可

  • PagerSnapHelper
   val pagerSnapHelper = PagerSnapHelper()
   pagerSnapHelper.attachToRecyclerView(mRvPager)
  • LinearSnapHelper
   val lineaSnapHelper = LinearSnapHelper()
   lineaSnapHelper.attachToRecyclerView(mRvLinear)

基础了解

SnapHelper自身为抽象类,同时继承了RecyclerView.OnFlingListener,内部实现了一些通用基类方法,you俩个实现子类,通过重写其中部分方法,从而达到对应的需求效果

  • PagerSnapHelper:类似ViewPager滑动效果,仅支持单条滑动!在 ViewPager控件中也可以看到PagerSnapHelper的身影
  • LinearSnapHelp:水平快速滑动列表,体验丝滑,当滑动停止后,ItemView 自动居中

在这里插入图片描述

OnFlingListener 仅拥有一个抽象方法

在这里插入图片描述

因为我只是通过源码方法命名 + 参考方法注释 简单理解,可能并不是很详细,有兴趣的可以前往早期一位前辈写的 让你明明白白的使用RecyclerView——SnapHelper详解

通过查看 SnapHelper 内部方法,简单分析一下方法作用范围(仅做部分解释,并不完全)

  • 支持 绑定RecyclerView
  • calculateDistanceToFinalSnap 测量移动距离
  • findSnapView 支持 定位移动的View
  • findTargetSnapPosition 支持定位移动后的数据(视图)角标
  • FlingListenerScrollListener 滑动监听&滑动速度监听

在这里插入图片描述

PagerSnapHelperLinearSnapHelper 除基类方法外,支持获取居中View、布局方向等

PagerSnapHelper 源码方法

在这里插入图片描述

LinearSnapHelper 源码方法

在这里插入图片描述

如果要自定义 SnapHelper 的话,需要重新以下三个抽象方法

package com.example.recyclerviewsnaphelper

import android.view.View
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SnapHelper

class OurHelper : SnapHelper() {
    //计算最终移动距离
    override fun calculateDistanceToFinalSnap(layoutManager: RecyclerView.LayoutManager, targetView: View): IntArray? {
        TODO("Not yet implemented")
    }

    //获取移动View
    override fun findSnapView(layoutManager: RecyclerView.LayoutManager?): View? {
        TODO("Not yet implemented")
    }

    //获取移动View的角标位置
    override fun findTargetSnapPosition(layoutManager: RecyclerView.LayoutManager?, velocityX: Int, velocityY: Int): Int {
        TODO("Not yet implemented")
    }
}

实践检验

RecyclerView 常规使用,仅加入了SnapHelper.attachToRecyclerView相关绑定

前置 ItemView

在这里插入图片描述

item_view

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="250dp"
    android:layout_height="100dp"
    android:paddingHorizontal="5dp">

    <TextView
        android:id="@+id/tv_data"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f98741"
        android:gravity="center"
        android:text="Item Data"
        android:textColor="#ffffff"
        android:textStyle="bold" />
</androidx.appcompat.widget.LinearLayoutCompat>

前置 Adapter

package com.example.recyclerviewsnaphelper

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class OurAdapter(private val dataList: MutableList<String>) : RecyclerView.Adapter<OurAdapter.OurViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OurViewHolder {
        return OurViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_view, parent,false))
    }

    override fun getItemCount(): Int {
        return dataList.size
    }

    override fun onBindViewHolder(holder: OurViewHolder, position: Int) {
        holder.itemView.findViewById<TextView>(R.id.tv_data).text=dataList[position]
    }

    inner class OurViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
}

使用方式

package com.example.recyclerviewsnaphelper

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSnapHelper
import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.HORIZONTAL

class MainActivity : AppCompatActivity() {
    var dataList = mutableListOf<String>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //数据模拟
        for (i in 0..15) {
            dataList.add("第${i + 1}页")
        }
        //RecyclerView基础配置
        pagerRecyclerSetting()
        layoutRecyclerSetting()
    }

    /**
     * RecyclerView基础配置:PagerSnapHelper示例
     * */
    private fun pagerRecyclerSetting() {
        val mRvPager = findViewById<RecyclerView>(R.id.rv_pager)
        var layoutManager = LinearLayoutManager(this)
        layoutManager.orientation = HORIZONTAL
        mRvPager.layoutManager = layoutManager
        val ourPagerAdapter = OurAdapter(dataList)
        mRvPager.adapter = ourPagerAdapter
        //添加SnapHelper相关辅助类
        val pagerSnapHelper = PagerSnapHelper()
        pagerSnapHelper.attachToRecyclerView(mRvPager)
    }

    /**
     * RecyclerView基础配置:LinearSnapHelper示例
     * */
    private fun layoutRecyclerSetting() {
        val mRvLinear = findViewById<RecyclerView>(R.id.rv_linear)
        var layoutManager = LinearLayoutManager(this)
        layoutManager.orientation = HORIZONTAL
        mRvLinear.layoutManager = layoutManager
        val ourLayoutAdapter = OurAdapter(dataList)
        mRvLinear.adapter = ourLayoutAdapter

        //添加SnapHelper相关辅助类
        val lineaSnapHelper = LinearSnapHelper()
        lineaSnapHelper.attachToRecyclerView(mRvLinear)
    }
}

activity_main

  • 预览图

在这里插入图片描述

  • layout布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center"
        android:text="PagerSnapHelper效果"
        android:textStyle="bold" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        tools:itemCount="10"
        tools:listitem="@layout/item_view" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginTop="50dp"
        android:gravity="center"
        android:text="LinearSnapHelper"
        android:textStyle="bold" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_linear"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        tools:itemCount="10"
        tools:listitem="@layout/item_view" />

</androidx.appcompat.widget.LinearLayoutCompat>
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到