<input id="0qass"><u id="0qass"></u></input>
  • <input id="0qass"><u id="0qass"></u></input>
  • <menu id="0qass"><u id="0qass"></u></menu>

    玩安卓從 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 使用方法基本都是下面這種:

    使用

    基本都是文章的列表,包括有下拉刷新和上拉加載,下拉刷新和上拉加載用的是下面這個庫:

    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 上看文檔。

    說到這里,終于要進入正題了!今天到底要實現一個什么功能呢?

    故事發生在上周末,我無聊在刷著自己寫的玩安卓,在看最新的一些文章,刷了好久,看了很多條目,突然想回到頂部,就只能一直往下滑了,想了下這也太不人性化了吧!好多軟件都有一鍵置頂的功能,也是很方便的,說干就干,那就來給玩安卓也添加一個一鍵置頂的功能吧!

    先來看看最終的實現效果吧!

    實現效果

    開始實現

    實現

    其實核心實現非常簡單,只需要下面的一行代碼:

    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 的代碼

    精致的結尾

    到這里本篇文章就要和大家說再見了,這篇文章雖然實現的功能很簡單,但也能提升一些用戶體驗!歡迎大家下載體驗。

    能力一般、水平有限,對大家有幫助的話別忘了三連,有 Github 賬號的幫忙點個 Star ,感激不盡!

    就這樣,下回再見!!!

    已標記關鍵詞 清除標記
    ??2020 CSDN 皮膚主題: 成長之路 設計師:Amelia_0503 返回首頁
    多乐彩