RecyclerView进阶使用(上拉加载)
RecyclerView進(jìn)階使用
- 前文
- 準(zhǔn)備
- 上拉加載
- 原理(addOnScrollListener)
- addOnScrollListener
- onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState)
- onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy)
- 方法1:
- 方法2
- 方法3
- 結(jié)尾
前文
正文不在這里,可以直接選擇跳過
記得上次更新還是在上次
可能是有人點(diǎn)贊才發(fā)現(xiàn)好久沒更新了
書接上文,上次說完了三個(gè)適配器的方法
最基本的的recyclerView使用相信可以運(yùn)用自如
可實(shí)際使用卻很復(fù)雜,比如上下拉刷新
這次就在源碼的角度解析一些上拉加載的實(shí)現(xiàn)方法
準(zhǔn)備
按照慣例先完成一個(gè)可以顯示的recycler
Activity部分
RecyclerActivity .java
Adapter部分
RecyclerAdapter4.java
Activity布局部分
activity_recycler.xml
item布局部分
recy_list3.xml
效果如圖
上拉加載
上拉,手指上滑,直到出現(xiàn)第20個(gè)ImagerView
加載,到第20個(gè),再加10個(gè),出現(xiàn)在下面
實(shí)際應(yīng)用場(chǎng)景常見于聊天記錄,商品列表
帶動(dòng)畫和回彈的過于復(fù)雜,本文只講原理
原理(addOnScrollListener)
recyclerview有個(gè)方法addOnScrollListener,如下
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {super.onScrollStateChanged(recyclerView, newState);}@Overridepublic void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);}});addOnScrollListener
添加一個(gè)偵聽器,該偵聽器將收到滾動(dòng)狀態(tài)或位置的任何更改的通知。
添加偵聽器的組件在完成后應(yīng)注意將其刪除。
擁有視圖所有權(quán)的其他組件可能會(huì)調(diào)用clearOnScrollListeners()以刪除所有附加的偵聽器
給RecyclerView添加滾動(dòng)監(jiān)聽,這么一說就很好理解了
當(dāng)滾動(dòng)到最后一個(gè)item時(shí),觸發(fā)某個(gè)方法,或者網(wǎng)絡(luò)請(qǐng)求獲取數(shù)據(jù),添加進(jìn)適配器的list中
最后那句話擁有視圖所有權(quán)的其他控件,也就是父控件/父布局,可能會(huì)在無意中刪除這個(gè)監(jiān)聽
目前沒有遇到這方面的問題,暫時(shí)不管
再來看看里面的兩個(gè)小方法
onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState)
當(dāng) RecyclerView 的滾動(dòng)狀態(tài)改變時(shí)調(diào)用的回調(diào)方法。
參數(shù):
recyclerView – 滾動(dòng)狀態(tài)已更改的 RecyclerView。
newState – 更新的滾動(dòng)狀態(tài)。 SCROLL_STATE_IDLE 、 SCROLL_STATE_DRAGGING或SCROLL_STATE_SETTLING 。
第一個(gè)是當(dāng)前滾動(dòng)的recy,也就是說這個(gè)監(jiān)聽器可以為多個(gè)recy服務(wù),可以復(fù)用
第二個(gè)是滾動(dòng)狀態(tài),三個(gè)常量的意思分別是
前兩個(gè)無非就是滾動(dòng)和靜止,第三個(gè)就是當(dāng)快速拖動(dòng)時(shí),手指離開了屏幕,但滾動(dòng)由于源碼設(shè)定的慣性仍在滾動(dòng)
onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy)
當(dāng) RecyclerView 滾動(dòng)時(shí)調(diào)用的回調(diào)方法。 這將在滾動(dòng)完成后調(diào)用。
如果在布局計(jì)算后可見項(xiàng)目范圍發(fā)生變化,也會(huì)調(diào)用此回調(diào)。 在這種情況下,dx 和 dy 將為 0。
參數(shù):
recyclerView – 滾動(dòng)的 RecyclerView。
dx – 水平滾動(dòng)量。
dy – 垂直滾動(dòng)量。
第二句話的意思是,recycler布局重新計(jì)算后,都會(huì)返回兩個(gè)0,比如剛進(jìn)入activity
到這里想必思路已經(jīng)出來了,只要知道最后一個(gè)item是否顯示就行
方法1:
通過布局管理器獲取到現(xiàn)在所顯示的item個(gè)數(shù),第一個(gè)item的位置(Position),一共有多少個(gè)item
總數(shù)<= 第一個(gè)pos+屏幕顯示的item
代碼如下
方法2
在適配器里計(jì)算每個(gè)view的高度
public class RecyclerAdapter4 extends RecyclerView.Adapter<RecyclerAdapter4.Holder> {//適配器數(shù)據(jù)private List<String> list;private Context context;//獲取整個(gè)recycler里的所有item高度總和,必須要拉到底private int itemHeightSum = 0;//避免recycler的銷毀和恢復(fù)影響高度計(jì)算private ArrayList<Boolean> load;public RecyclerAdapter4(Context context) {this.context = context;list = new ArrayList<>();load= new ArrayList<>();}/*** 創(chuàng)建布局*/@NonNull@Overridepublic Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {//直接簡(jiǎn)寫成一行 如果看不懂可以回看《初步使用》文章return new Holder(LayoutInflater.from(context).inflate(R.layout.recy_list3, parent, false));}@SuppressLint("SetTextI18n")@Overridepublic void onBindViewHolder(@NonNull Holder holder, int position) {//顯示pos對(duì)應(yīng)的textviewholder.text.setText("這是第" + (position + 1) + "個(gè)ImageView -> ");//view.post是view渲染出來后執(zhí)行,如果直接獲取高度是0holder.itemView.post(() -> {//load中第pos個(gè)計(jì)算過高度,不予計(jì)算if (load.get(position)){//只計(jì)算一次load.add(position,false);//自增高度itemHeightSum += holder.itemView.getHeight();}});}@Overridepublic int getItemCount() {return list.size();}/*** 添加數(shù)據(jù)*/public void addData(String str) {list.add(str);//新添加的需要計(jì)算 給trueload.add(true);notifyDataSetChanged();}/*** 獲取所有item的高*/public int getItemHeightSum() {return itemHeightSum;}/*** 自定義的Holder*/public class Holder extends RecyclerView.ViewHolder {//全局變量 供onBindViewHolder使用public TextView text;public ImageView img;public Holder(@NonNull View itemView) {super(itemView);//綁定需要的控件text = itemView.findViewById(R.id.text);img = itemView.findViewById(R.id.img);//....}} }原理就是通過adapter的每次復(fù)用,記錄下哪個(gè)沒有計(jì)算高度
滑到底時(shí)全部item都計(jì)算過
注意添加數(shù)據(jù)必須使用自己寫的addData方法,又或者必須在對(duì)應(yīng)的位置load.add(true)
另外需要注意的是 item不能設(shè)置外邊距 否則高度會(huì)有出入
另外需要注意的是 item不能設(shè)置外邊距 否則高度會(huì)有出入
另外需要注意的是 item不能設(shè)置外邊距 否則高度會(huì)有出入
avtivity的代碼如下需要在onScrollStateChanged中添加判斷和activity判斷
public class RecyclerActivity extends AppCompatActivity {String TAG = "Tag";RecyclerAdapter4 adapter4;LinearLayoutManager layoutManager;RecyclerView recyclerView;boolean load = false;int y = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_recycler);initRecycler();onBottom();}private void initRecycler() {//省略,代碼在上面的準(zhǔn)備}/*** 監(jiān)聽到底*/private void onBottom() {/*** 添加一個(gè)偵聽器,該偵聽器將收到滾動(dòng)狀態(tài)或位置的任何更改的通知。* 添加偵聽器的組件在完成后應(yīng)注意將其刪除。* 擁有視圖所有權(quán)的其他組件可能會(huì)調(diào)用clearOnScrollListeners()以刪除所有附加的偵聽器** 可以將 OnScrollListener 添加到 RecyclerView* 以在該 RecyclerView 上發(fā)生滾動(dòng)事件時(shí)接收消息。* */recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {/*** 當(dāng) RecyclerView 的滾動(dòng)狀態(tài)改變時(shí)調(diào)用的回調(diào)方法。* 參數(shù):* recyclerView – 滾動(dòng)狀態(tài)已更改的 RecyclerView。* newState – 更新的滾動(dòng)狀態(tài)。 SCROLL_STATE_IDLE 、 SCROLL_STATE_DRAGGING或SCROLL_STATE_SETTLING 。* */@Overridepublic void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {super.onScrollStateChanged(recyclerView, newState);switch (newState) {case RecyclerView.SCROLL_STATE_IDLE://總高度等于 全部item的高度Log.i(TAG, "總高度 " + adapter4.getItemHeightSum());//y = recycler的實(shí)際高度 + 滑動(dòng)的距離Log.i(TAG, "y : " + y);//判斷recycler是否滑到底 //到底時(shí)recycler的實(shí)際高度 + 滑動(dòng)的距離 == 全部item的高度if (y >= adapter4.getItemHeightSum() && load) {load = false;//避免重復(fù)刷新Toast.makeText(RecyclerActivity.this,"刷新",Toast.LENGTH_SHORT).show();addRecyclerData();}Log.i(TAG, "靜止");case RecyclerView.SCROLL_STATE_DRAGGING:Log.i(TAG, "滑動(dòng)");case RecyclerView.SCROLL_STATE_SETTLING:Log.i(TAG, "慣性");}}/*** 當(dāng) RecyclerView 滾動(dòng)時(shí)調(diào)用的回調(diào)方法。 這將在滾動(dòng)完成后調(diào)用。* 如果在布局計(jì)算后可見項(xiàng)目范圍發(fā)生變化,也會(huì)調(diào)用此回調(diào)。 在這種情況下,dx 和 dy 將為 0。* */@Overridepublic void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);//添加滑動(dòng)距離 此次不必限制 往上減往下加y += dy;}});}/*** 當(dāng)窗口獲得焦點(diǎn)時(shí)* */@Overridepublic void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);//獲取recycler的高度y = recyclerView.getHeight();}/*** 添加十條數(shù)據(jù)* */private void addRecyclerData(){for (int i=0;i<10;i++){adapter4.addData("0000");}load = true;} }效果圖
方法3
使用canScrollVertically
在onScrollStateChanged中添加如下代碼
結(jié)尾
沒有花里胡哨的動(dòng)畫或者回彈加載
簡(jiǎn)單的監(jiān)聽到底部,如果需要可以根據(jù)上篇的添加布局實(shí)現(xiàn)加載動(dòng)畫
github上也有許多開源的上拉加載
本文僅限原理分析和實(shí)現(xiàn)方法
本來想加下拉刷新的講解,字?jǐn)?shù)過多,只能等下篇
最后
對(duì)本文有任何意見或疑問,或者認(rèn)為其中說法有誤,歡迎在評(píng)論區(qū)留言!!!
轉(zhuǎn)載請(qǐng)注明出處!!
總結(jié)
以上是生活随笔為你收集整理的RecyclerView进阶使用(上拉加载)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: KaggleM5 Forecasting
- 下一篇: 一个可以免费去除图片背景的网站