当前位置:   article > 正文

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

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

之前一直没注意 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)
  • 1
  • 2
  • LinearSnapHelper
   val lineaSnapHelper = LinearSnapHelper()
   lineaSnapHelper.attachToRecyclerView(mRvLinear)
  • 1
  • 2

基础了解

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")
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

实践检验

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

前置 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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

使用方式

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)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/174642
推荐阅读
相关标签
  

闽ICP备14008679号