玩安卓从 0 到 1 之列表一键置顶

简介: 玩安卓从 0 到 1 之列表一键置顶

前言

系列文章

这篇文章是这个系列的第六篇文章了,下面是前五篇文章:

1、玩安卓从 0 到 1 之总体概览

2、玩安卓从 0 到 1 之项目首页

3、玩安卓从 0 到 1 之首页框架搭建。

4、玩安卓从 0 到 1 之架构思考

5、玩安卓从 0 到 1 之适配器思考

按照惯例,放一下 Github 地址和 apk 下载地址吧!

apk 下载地址:www.pgyer.com/llj2

Github地址:github.com/zhujiang521…

前因后果

RecyclerView 大家平时都会使用,在本项目中 RecyclerView 使用方法基本都是下面这种:

98388abcc9dc2e585431d1c64af21807.gif

基本都是文章的列表,包括有下拉刷新和上拉加载,下拉刷新和上拉加载用的是下面这个库:

SmartRefreshLayout

下面是这个库的依赖:

api  'com.scwang.smart:refresh-layout-kernel:2.0.1'      //核心必须依赖
api  'com.scwang.smart:refresh-header-classics:2.0.1'    //经典刷新头
api  'com.scwang.smart:refresh-footer-classics:2.0.1'    //经典加载

这个库的使用方法在下面会有提及,不过更建议去官方 Github 上看文档。

说到这里,终于要进入正题了!今天到底要实现一个什么功能呢?

故事发生在上周末,我无聊在刷着自己写的玩安卓,在看最新的一些文章,刷了好久,看了很多条目,突然想回到顶部,就只能一直往下滑了,想了下这也太不人性化了吧!好多软件都有一键置顶的功能,也是很方便的,说干就干,那就来给玩安卓也添加一个一键置顶的功能吧!

先来看看最终的实现效果吧!


432d4ae2408afe6a8b2137f9f1048baf.gif

开始实现

实现

其实核心实现非常简单,只需要下面的一行代码:

mToTopRecycleView.smoothScrollToPosition(0)

这个大家都会,我就不多解释了。

我展示一键置顶按钮的时机是只有在上滑的时候才会展示,平时不展示,下滑的时候也不展示,,当上滑到顶部的时候也不展示。为什么这样设置呢?因为我个人认为只有用户向上滑了才证明用户又可能想回到顶部。

那么下面就来看下怎样设置展示时机吧!

mToTopRecycleView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
   override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
       if (!recyclerView.canScrollVertically(-1)) {
           // 上滑到顶部
       } else if (dy < 0) {
           // 上滑
       } else if (dy > 0) {
           // 下滑
       }
    }
})

其实到这里基本已经实现功能了,只需要在布局中添加一个按钮,然后给按钮添加下点击事件就行了。但是。。。。。。

凡事就怕但是,如果只是这一个页面需要一键置顶的话那就简单了,在这个页面布局中加一个按钮就好,但是文章列表有很多个页面啊,不止一个!而且都有下拉刷新和上拉加载的功能,本着程序员的懒劲,还是少写点吧,抽一个控件出来吧,别的地方如果需要使用的话直接用这个控件就行!那么就开始吧!

先来想一下这个控件的父类该是谁,肯定是一个 ViewGroup,其实布局并不难,那就使用 FrameLayout 吧!

class ToTopRecyclerView @JvmOverloads constructor(
    private val mContext: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(mContext, attrs, defStyleAttr)

定义好类就完成了一大半了,为啥呢?万事开头难嘛!头都开了,还怕啥!

接下来在 init 方法中将写好的布局加载进来:

init{
    View.inflate(mContext, R.layout.layout_to_top, this)
}

来看下布局文件吧:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <com.scwang.smart.refresh.layout.SmartRefreshLayout
        android:id="@+id/toTopSmartRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/toTopRecycleView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </com.scwang.smart.refresh.layout.SmartRefreshLayout>
    <ImageView
        android:id="@+id/toTopIvClick"
        android:layout_width="@dimen/dp_40"
        android:layout_height="@dimen/dp_40"
        android:layout_gravity="right|bottom"
        android:layout_margin="@dimen/dp_20"
        android:background="@drawable/to_top_bg"
        android:padding="@dimen/dp_8"
        android:src="@drawable/ic_baseline_vertical_align_top_24"
        android:visibility="gone" />
</merge>

为啥最外面是 merge 就不说了,这要是不会赶快再去看看基础吧。

下面就是 findViewById 了,这个太简单就不贴代码了,浪费时间。

接下来需要想一下咱们想让这个控件完成什么功能,思来想去一共有以下几个功能:

  • 设置 RecyclerView 的 adapter
  • 设置上拉加载和下拉刷新的事件
  • 设置 RecyclerView 的 LayoutManager

可能有人会说,一键置顶不需要吗?如果需要的话那咱们写这个控件的意义何在啊!

下面就根据上面的列表顺序来一个一个写吧!

首先是设置 RecyclerView 的 adapter:

fun setAdapter(adapter: RecyclerView.Adapter<BaseListAdapter.ViewHolder>) {
    mToTopRecycleView.adapter = adapter
}

代码很简单,只是提供给外部一个设置 adapter 的入口。

然后是设置上拉加载和下拉刷新的事件:

fun onRefreshListener(onRefreshListener: () -> Unit, onLoadMoreListener: () -> Unit) {
    mToTopSmartRefreshLayout.apply {
        setOnRefreshListener { reLayout ->
            reLayout.finishRefresh(measureTimeMillis {
                onRefreshListener.invoke()
            }.toInt())
        }
        setOnLoadMoreListener { reLayout ->
            val time = measureTimeMillis {
                onLoadMoreListener.invoke()
            }.toInt()
            reLayout.finishLoadMore(if (time > mLoadTime) time else mLoadTime)
        }
    }
}

这个方法有必要说下了,这就是文章开头所说那个库的使用方法。

这块使用了一个高阶函数,方法参数是两个函数,通过名称就可以知道第一个是刷新的函数,第二个是加载更多的函数。

最后是设置 RecyclerView 的 LayoutManager,为了省事我决定将这个函数写的方便一些,别的地方调用的时候只需要传入布尔值或者 int ,然后通过判断设置不同的 LayoutManager。

思来想去,本项目中的 RecyclerView 只用到了两种 LayoutManager,分别是 LinearLayoutManager(竖屏) 和 StaggeredGridLayoutManager(横屏),那么就用布尔值作为参数来判断使用哪种 LayoutManager 吧,下面是方法的代码:

fun setRecyclerViewLayoutManager(isLinearLayout: Boolean) {
    if (isLinearLayout) {
        mToTopRecycleView.layoutManager = LinearLayoutManager(context)
    } else {
        val spanCount = 2
        val layoutManager =
            StaggeredGridLayoutManager(spanCount, StaggeredGridLayoutManager.VERTICAL)
        mToTopRecycleView.layoutManager = layoutManager
        layoutManager.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_NONE
    }
}

OK,这就差不多了。

使用

实现完成了就该使用了,实践是检验真理的唯一标准!

先给首页尝试下,添加到布局中:

<com.zj.core.view.custom.ToTopRecyclerView
    android:id="@+id/homeToTopRecyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

注意!上面写的下面就要进行调用了!

homeToTopRecyclerView.setAdapter(articleAdapter)
homeToTopRecyclerView.onRefreshListener({
    page = 1
    getArticleList(true)
}, {
    page++
    getArticleList(true)
})
homeToTopRecyclerView.setRecyclerViewLayoutManager(true)

还是那句话,如果只是一个地方调用,怎么写都是对的,但如果很多地方调用的话抽出来就很有必要了!

大家可以下载项目看下历史提交,省了很多代码。

本篇 View 的代码

精致的结尾

到这里本篇文章就要和大家说再见了,这篇文章虽然实现的功能很简单,但也能提升一些用户体验!





目录
相关文章
|
5月前
|
XML Java Android开发
Android Studio App开发中改造已有的控件实战(包括自定义支付宝月份选择器、给翻页栏添加新属性、不滚动的列表视图 附源码)
Android Studio App开发中改造已有的控件实战(包括自定义支付宝月份选择器、给翻页栏添加新属性、不滚动的列表视图 附源码)
54 1
|
5月前
|
XML Java Android开发
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
45 0
|
5月前
|
XML Java Android开发
Android Studio App入门之列表视图ListView的讲解及实战(附源码 超详细必看)
Android Studio App入门之列表视图ListView的讲解及实战(附源码 超详细必看)
99 0
|
1月前
|
存储 缓存 Android开发
构建高效的Android应用:采用RecyclerView优化列表显示
【4月更文挑战第2天】 在移动开发领域,列表显示是最常见的用户界面组件之一。对于Android平台而言,RecyclerView因其高效、灵活的特点而备受开发者青睐。本文将深入探讨如何利用RecyclerView在Android应用中实现流畅的列表滚动,以及通过各种优化策略来提升性能和用户体验。我们将从基本概念出发,逐步展开如何自定义适配器、视图持有者,以及利用布局管理器来实现复杂的列表布局。此外,还将讨论如何通过异步加载、缓存机制和动态数据更新来进一步优化性能。
14 1
|
5月前
|
XML Java Android开发
Android Studio App开发之列表类视图中基本适配器BaseAdapter的使用及实战(附源码 超详细)
Android Studio App开发之列表类视图中基本适配器BaseAdapter的使用及实战(附源码 超详细)
54 0
|
9月前
|
Android开发
Android 根据时间的升序或降序把数据列表进行排序
Android 根据时间的升序或降序把数据列表进行排序
94 0
|
10月前
|
XML Java 数据处理
Android:RecyclerView封装,打造列表极简加载
此库的封装,除了刷新加载库使用了SmartRefreshLayout,其他的都是自己从0到1的开发,目前,自己已经在项目中使用,暂时没有出现任何问题,当然了,后续,也会不断的对其进行优化,增加一些其他的功能,希望有需要的小伙伴,长期关注。
241 0
|
12月前
|
Android开发
全网最优雅安卓列表项可见性检测
全网最优雅安卓列表项可见性检测
120 0
|
12月前
|
Android开发
Bug日志(四)——Android 防止多次点击(另解决多个列表子项点击)
在用户使用 应用的时候,经常会出现点击过快且多次点击同一控件的情况, 一方面这是因为应用或手机当前有些卡顿,网络卡啥的 另一方面也可能是由于很多应用并没有设置按钮点击时的 selector 或者其它按钮响应方式(例如点击按钮时按钮放大,常见于游戏),导致用户误认为没有点击到当前按钮。(比如使用selector再点击后更换背景颜色,图片等等)