自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

詳解RecyclerView下拉刷新與上拉更多

開(kāi)發(fā) 開(kāi)發(fā)工具
在原來(lái)的文章中我提及了如何使用RecyclerView添加header與footer,今天我們來(lái)更深入的擴(kuò)展一下使用RecyclerView實(shí)現(xiàn)常用的下拉刷新與上拉加載更多的功能。當(dāng)然這些功能的實(shí)現(xiàn)也是基于前面的RecyclerView添加header與footer為基礎(chǔ)來(lái)實(shí)現(xiàn)的。

 [[169565]]

前言

在原來(lái)的文章中我提及了如何使用RecyclerView添加header與footer,今天我們來(lái)更深入的擴(kuò)展一下使用RecyclerView實(shí)現(xiàn)常用的下拉刷新與上拉加載更多的功能。當(dāng)然這些功能的實(shí)現(xiàn)也是基于前面的RecyclerView添加header與footer為基礎(chǔ)來(lái)實(shí)現(xiàn)的,不是很了解的可以先看看前面的文章可能能更好的幫助理解。

依賴

為了方法大家的使用我已經(jīng)把他上傳到Jcenter中了,所以大家可以調(diào)用下面的代碼了直接獲取使用: 

  1. compile 'com.idisfkj.enchancerecyclerview:mylibrary:1.1.1' 

EnhanceRecyclerView

我將這個(gè)擴(kuò)展的RecyclerView命名為EnhanceRecyclerView,繼承RecyclerView。我們知道既然要實(shí)現(xiàn)下拉刷新與上拉更多自然先要實(shí)現(xiàn)頭部與尾部的布局,所以我們先利用前面的知識(shí)來(lái)為EnhanceRecycleView添加header與footer 

  1. public void initView() { 
  2.         View headerView = LayoutInflater.from(getContext()).inflate(R.layout.head_layout, null); 
  3.         View footerView = LayoutInflater.from(getContext()).inflate(R.layout.footer_layout, null); 
  4.         addHeaderView(headerView); 
  5.         addFooterView(footerView); 
  6.     } 

 其中的布局文件就不多說(shuō)了,至于addHeaderView與addFooterView方法可以查看我前面的那篇文章,有詳細(xì)的介紹

設(shè)置監(jiān)聽(tīng)器

既然要實(shí)現(xiàn)下拉刷新與上拉加載,自然少不了對(duì)監(jiān)聽(tīng)器的處理,所以下面來(lái)詳細(xì)介紹下對(duì)監(jiān)聽(tīng)器OnScrollListener與OnTouchListener的處理。

OnScrollListener

為EnhanceRecyclerView添加addOnScrollListener實(shí)現(xiàn)其中的onScrollStateChanged與onScrolled方法。

onScrolled

在onScrolled中我們主要做的是獲取EnhanceRcyclerView中item的總數(shù)量、視圖顯示中的***個(gè)item在EnhanceRecyclerView中所處的位置與視圖顯示中***一個(gè)item在EnhanceRecyclerView中所處的位置。

對(duì)于item的總數(shù)量很好獲取直接調(diào)用

 

  1. totalCount = getLayoutManager().getItemCount(); 

由于RecyclerView能實(shí)現(xiàn)LinearLayoutManager、GridLayoutManager與StaggeredGridLayoutManager不同的布局,所以另外兩個(gè)要根據(jù)不同的manager來(lái)獲取,還是看具體代碼吧 

  1. if (getLayoutManager() instanceof LinearLayoutManager) { 
  2.                     lastItem = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition(); 
  3.                     firstVisible = ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition(); 
  4.                 } else { 
  5.                     into = ((StaggeredGridLayoutManager) getLayoutManager()).findLastVisibleItemPositions(into); 
  6.                     firstInto = ((StaggeredGridLayoutManager) getLayoutManager()).findFirstVisibleItemPositions(firstInto); 
  7.                     lastItem = into[0]; 
  8.                     firstVisible = firstInto[0]; 
  9.                 } 

 onScrollStateChanged

獲取到了那三個(gè)關(guān)鍵數(shù)據(jù)以后,就可以在onScrollStateChanged中實(shí)現(xiàn)具體的邏輯,在這個(gè)方法中主要實(shí)現(xiàn)的是對(duì)上拉加載更多的處理 

  1. if (lastItem == adapter.getItemCount() + 1 && newState == RecyclerView.SCROLL_STATE_IDLE && !isLoad) { 
  2.                     ViewGroup.LayoutParams params = getFooterView(0).getLayoutParams(); 
  3.                     params.width = RecyclerView.LayoutParams.MATCH_PARENT; 
  4.                     params.height = RecyclerView.LayoutParams.WRAP_CONTENT; 
  5.                     getFooterView(0).setLayoutParams(params); 
  6.                     getFooterView(0).setVisibility(View.VISIBLE); 
  7.                     smoothScrollToPosition(totalCount); 
  8.                     isLoad = true
  9.                     loadMoreListener.onLoadMore(); 
  10.                 } 
  11.                 if (firstVisible == 0) { 
  12.                     isTop = true
  13.                 } else { 
  14.                     isTop = false
  15.                     RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) getHeaderView(0).getLayoutParams(); 
  16.                     params.width = RecyclerView.LayoutParams.MATCH_PARENT; 
  17.                     params.height = RecyclerView.LayoutParams.WRAP_CONTENT; 
  18.                     params.setMargins(0, -getHeaderView(0).getHeight(), 0, 0); 
  19.                     getHeaderView(0).setLayoutParams(params); 
  20.                 } 

 簡(jiǎn)單說(shuō)明下,核心就是判斷l(xiāng)astItem是否處在***的位置,如果是的話就繼續(xù)加載更多的操作,這里提供了一個(gè)對(duì)數(shù)據(jù)處理的接口所以只要實(shí)現(xiàn)loadMoreListener.onLoadMore();即可。

上拉加載更多核心就是這么多,其它的可以查看源碼

OnTouchListener

這個(gè)監(jiān)聽(tīng)器主要是對(duì)下拉刷新進(jìn)行處理。我們要分別對(duì)其中我們所熟悉的MotionEvent.ACTION_DOWN、MotionEvent.ACTION_MOVE與MotionEvent.ACTION_UP進(jìn)行處理。ACTION_DOWN就是簡(jiǎn)單的獲取按下的坐標(biāo)位置,這里就不多說(shuō)了,下面主要的針對(duì)另外的兩個(gè)進(jìn)行簡(jiǎn)單說(shuō)明。

ACTION_MOVE

這做的邏輯就是對(duì)觸摸后的處理,根據(jù)滑動(dòng)的距離來(lái)動(dòng)態(tài)的改變header的文本與布局視圖的顯示。 

  1. public void touchMove(MotionEvent event) { 
  2.         endY = event.getY(); 
  3.         moveY = endY - startY; 
  4.         //防止item向上滑出 
  5.         if (moveY > 0 && !isRefreshing) { 
  6.             //防止回退文本顯示異常 
  7.             scrollToPosition(0); 
  8.  
  9.             if (getHeaderView(0).getVisibility() == GONE) 
  10.                 getHeaderView(0).setVisibility(VISIBLE); 
  11.  
  12.             RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) getHeaderView(0).getLayoutParams(); 
  13.             params.width = RecyclerView.LayoutParams.MATCH_PARENT; 
  14.             params.height = RecyclerView.LayoutParams.WRAP_CONTENT; 
  15.             //使header隨moveY的值從頂部漸漸出現(xiàn) 
  16.             if (moveY >= 400) { 
  17.                 moveY = 100 + moveY / 4; 
  18.             } else { 
  19.                 moveY = moveY / 2; 
  20.             } 
  21.             viewHeight = getHeaderView(0).getHeight(); 
  22.             if (viewHeight <= 0) 
  23.                 viewHeight = 130; 
  24.             moveY = moveY - viewHeight; 
  25.             params.setMargins(0, (int) moveY, 0, 0); 
  26.             getHeaderView(0).setLayoutParams(params); 
  27.             if (moveY > 80) { 
  28.                 text.setText(getResources().getString(R.string.release_to_refresh)); 
  29.             } else { 
  30.                 text.setText(getResources().getString(R.string.pull_to_refresh)); 
  31.             } 
  32.         } else { 
  33.             if (getHeaderView(0).getVisibility() != GONE && !isRefreshing) { 
  34.                 getHeaderView(0).setVisibility(GONE); 
  35.             } 
  36.         } 
  37.     } 

 至于下拉時(shí)與頂部的距離變化是通過(guò)設(shè)置margin來(lái)動(dòng)態(tài)改變的。

ACTION_UP

***的觸摸處理就是在離開(kāi)屏幕時(shí)根據(jù)滑動(dòng)的距離,是否調(diào)用加載數(shù)據(jù)的接口,或者隱藏下拉刷新頭部,具體還是看代碼吧。 

  1. public void touchUp() { 
  2.         if (!isRefreshing && (endY -startY) != 0 ) { 
  3.  
  4.             RecyclerView.LayoutParams params1 = (RecyclerView.LayoutParams) getHeaderView(0).getLayoutParams(); 
  5.             params1.width = RecyclerView.LayoutParams.MATCH_PARENT; 
  6.             params1.height = RecyclerView.LayoutParams.WRAP_CONTENT; 
  7.  
  8.             if (moveY >= 80) { 
  9.                 text.setText(getResources().getString(R.string.refreshing)); 
  10.                 params1.setMargins(0, 0, 0, 0); 
  11.                 isRefreshing = true
  12.                 //刷新數(shù)據(jù) 
  13.                 pullToRefresh.onRefreshing(); 
  14.             } else { 
  15.                 if (viewHeight <= 0) 
  16.                     viewHeight = 130; 
  17.                 params1.setMargins(0, -viewHeight, 0, 0); 
  18.                 getHeaderView(0).setVisibility(GONE); 
  19.             } 
  20.             getHeaderView(0).setLayoutParams(params1); 
  21.         } 
  22.     } 

 代碼中重要的地方都有指出相信都能看懂,這樣下拉與上拉的邏輯就基本實(shí)現(xiàn)了,下面來(lái)看接口的設(shè)計(jì)吧

下拉與上拉接口 

  1. public interface PullToRefreshListener { 
  2.         void onRefreshing(); 
  3.     } 
  4.  
  5.     public void setPullToRefreshListener(PullToRefreshListener pullToRefresh) { 
  6.         if (loadMoreListener == null) { 
  7.             initListener(); 
  8.         } 
  9.         this.pullToRefresh = pullToRefresh; 
  10.     } 
  11.  
  12.     public interface LoadMoreListener { 
  13.         void onLoadMore(); 
  14.     } 
  15.  
  16.     public void setLoadMoreListener(LoadMoreListener loadMoreListener) { 
  17.         if (pullToRefresh == null) { 
  18.             initListener(); 
  19.         } 
  20.         this.loadMoreListener = loadMoreListener; 
  21.     } 

 在運(yùn)用是添加接口監(jiān)聽(tīng)時(shí)初始化前面為EnhanceRecyclerView所設(shè)置的監(jiān)聽(tīng)。

狀態(tài)重置設(shè)置

在調(diào)用下拉刷新或者上拉加載更多之后,我們?yōu)槠錁?gòu)造通用方法實(shí)現(xiàn),狀態(tài)的重置與數(shù)據(jù)的更新,方便統(tǒng)一調(diào)用。 

  1. public void setLoadMoreComplete() { 
  2.         RecyclerView.LayoutParams params = (LayoutParams) getFooterView(0).getLayoutParams(); 
  3.         params.width = 0; 
  4.         params.height = 0; 
  5.         getFooterView(0).setLayoutParams(params); 
  6.         getFooterView(0).setVisibility(View.GONE); 
  7.         this.getAdapter().notifyDataSetChanged(); 
  8.         isLoad = false
  9.     } 
  10.  
  11.     public void setRefreshComplete() { 
  12.         RecyclerView.LayoutParams params1 = (RecyclerView.LayoutParams) getHeaderView(0).getLayoutParams(); 
  13.         params1.width = RecyclerView.LayoutParams.MATCH_PARENT; 
  14.         params1.height = RecyclerView.LayoutParams.WRAP_CONTENT; 
  15.         params1.setMargins(0, -getHeaderView(0).getHeight(), 0, 0); 
  16.         getHeaderView(0).setLayoutParams(params1); 
  17.         getHeaderView(0).setVisibility(GONE); 
  18.         this.getAdapter().notifyDataSetChanged(); 
  19.         isRefreshing = false
  20.     } 

 所用工作已經(jīng)完成下面來(lái)做個(gè)調(diào)用示范

使用

xml中引用 

  1. <com.idisfkj.mylibrary.EnhanceRecyclerView 
  2.         android:id="@+id/recyclerView" 
  3.         android:layout_width="match_parent" 
  4.         android:layout_height="match_parent"
  5. </com.idisfkj.mylibrary.EnhanceRecyclerView> 

 設(shè)置監(jiān)聽(tīng) 

  1. mRecyclerView.setPullToRefreshListener(new com.idisfkj.mylibrary.EnhanceRecyclerView.PullToRefreshListener() { 
  2.             @Override 
  3.             public void onRefreshing() { 
  4.                 refreshData(); 
  5.             } 
  6.         }); 
  7.         mRecyclerView.setLoadMoreListener(new EnhanceRecyclerView.LoadMoreListener() { 
  8.             @Override 
  9.             public void onLoadMore() { 
  10.                 loadMoreData(); 
  11.             } 
  12.         }); 

 

refreshData()與loadMoreData()加載數(shù)據(jù)的邏輯就不展示了,只是要記住在請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)完之后要在他們中調(diào)用相應(yīng)的mRecyclerView.setRefreshComplete()與 mRecyclerView.setLoadMoreComplete()來(lái)重置狀態(tài)。

至于其他的Adapter、LayoutManager等的設(shè)置就不多說(shuō)了,與原生的RecyclerView是一樣的。 

總結(jié)

其實(shí)總的來(lái)說(shuō)難點(diǎn)有兩個(gè)

添加header與footer。這個(gè)前面已經(jīng)攻克了,而且原理也相對(duì)簡(jiǎn)單

實(shí)現(xiàn)觸摸與滑動(dòng)監(jiān)聽(tīng)邏輯。這個(gè)主要是對(duì)邏輯的理解,對(duì)整個(gè)刷新的過(guò)程做個(gè)整體分析,就能很好的理解上面的代碼。對(duì)其中視圖的動(dòng)態(tài)顯示做相應(yīng)的變化與接口的調(diào)用就能很好的處理這些工程。

當(dāng)然上面的實(shí)現(xiàn)可能還有瑕疵,希望指出,我會(huì)相應(yīng)的做修改或者你們修改后可以提交給我,我統(tǒng)一做修改,謝謝!

責(zé)任編輯:龐桂玉 來(lái)源: segmentfault
相關(guān)推薦

2015-03-23 18:11:39

UITableViewswift下拉刷新

2016-12-26 15:39:35

Android下拉刷新頭部廣告位

2021-12-01 10:02:57

鴻蒙HarmonyOS應(yīng)用

2018-07-02 12:49:33

刷新控件動(dòng)畫(huà)

2021-09-02 10:00:42

鴻蒙HarmonyOS應(yīng)用

2013-07-17 16:33:02

下拉刷新listvie滾動(dòng)到底部加載Android開(kāi)發(fā)學(xué)習(xí)

2017-07-25 16:08:18

AndroidRecyclervie

2015-04-22 10:57:22

androidSwipeRefres

2013-01-18 16:48:25

拉里·佩奇Google谷歌

2015-05-13 09:36:18

js模擬手機(jī)下拉刷新

2024-07-02 10:00:55

2012-03-28 22:16:54

蘋(píng)果

2023-03-27 18:33:47

客服IM消息

2015-03-19 10:12:36

下拉刷新開(kāi)源組件

2009-06-16 09:41:00

2012-05-02 14:41:04

jQuery

2023-06-25 18:52:48

2018-02-23 10:30:15

Linux命令網(wǎng)絡(luò)連接
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)