日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

RecyclerView进阶使用(上拉加载)

發布時間:2023/12/31 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RecyclerView进阶使用(上拉加载) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

RecyclerView進階使用

  • 前文
  • 準備
  • 上拉加載
    • 原理(addOnScrollListener)
      • addOnScrollListener
      • onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState)
      • onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy)
      • 方法1:
      • 方法2
      • 方法3
  • 結尾

前文

正文不在這里,可以直接選擇跳過
記得上次更新還是在上次
可能是有人點贊才發現好久沒更新了
書接上文,上次說完了三個適配器的方法
最基本的的recyclerView使用相信可以運用自如
可實際使用卻很復雜,比如上下拉刷新
這次就在源碼的角度解析一些上拉加載的實現方法

準備

按照慣例先完成一個可以顯示的recycler

Activity部分
RecyclerActivity .java

public class RecyclerActivity extends AppCompatActivity {RecyclerAdapter4 adapter4;LinearLayoutManager layoutManager;RecyclerView recyclerView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_recycler);initRecycler();}private void initRecycler() {recyclerView = findViewById(R.id.recycler);layoutManager = new LinearLayoutManager(this);//直接在括號里實例化一個適配器 泛型是自定義的Holderadapter4 = new RecyclerAdapter4(this);//為recycler設置適配器和布局管理器recyclerView.setAdapter(adapter4);recyclerView.setLayoutManager(layoutManager);//開始添加數據 初始數據二十條,滑到底部增加十條//調用adapter中的addData方法for (int i = 0; i < 20; i++) {adapter4.addData("str");}} }

Adapter部分
RecyclerAdapter4.java

public class RecyclerAdapter4 extends RecyclerView.Adapter<RecyclerAdapter4.Holder> {//適配器數據private List<String> list;private Context context;public RecyclerAdapter4(Context context) {this.context = context;list = new ArrayList<>();}/*** 創建布局*/@NonNull@Overridepublic Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {//直接簡寫成一行 如果看不懂可以回看《初步使用》文章return new Holder(LayoutInflater.from(context).inflate(R.layout.recy_list3, parent, false));}@SuppressLint("SetTextI18n")@Overridepublic void onBindViewHolder(@NonNull Holder holder, int position) {//顯示pos對應的textviewholder.text.setText("這是第" + (position + 1) + "個ImageView -> ");}@Overridepublic int getItemCount() {return list.size();}/*** 添加數據*/public void addData(String str) {list.add(str);notifyDataSetChanged();}/*** 自定義的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);//....}} }

Activity布局部分
activity_recycler.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recycler"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout>

item布局部分
recy_list3.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/layout"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:layout_margin="10dp"android:orientation="horizontal"><TextViewandroid:id="@+id/text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="這是第0個ImageView -> "android:textSize="20dp" /><ImageViewandroid:id="@+id/img"android:layout_width="20dp"android:layout_height="20dp"android:layout_gravity="center"android:src="@color/black" /></LinearLayout>

效果如圖

上拉加載

上拉,手指上滑,直到出現第20個ImagerView
加載,到第20個,再加10個,出現在下面
實際應用場景常見于聊天記錄,商品列表
帶動畫和回彈的過于復雜,本文只講原理

原理(addOnScrollListener)

recyclerview有個方法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

添加一個偵聽器,該偵聽器將收到滾動狀態或位置的任何更改的通知。
添加偵聽器的組件在完成后應注意將其刪除。
擁有視圖所有權的其他組件可能會調用clearOnScrollListeners()以刪除所有附加的偵聽器

給RecyclerView添加滾動監聽,這么一說就很好理解了
當滾動到最后一個item時,觸發某個方法,或者網絡請求獲取數據,添加進適配器的list中
最后那句話擁有視圖所有權的其他控件,也就是父控件/父布局,可能會在無意中刪除這個監聽
目前沒有遇到這方面的問題,暫時不管

再來看看里面的兩個小方法

onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState)

當 RecyclerView 的滾動狀態改變時調用的回調方法。
參數:
recyclerView – 滾動狀態已更改的 RecyclerView。
newState – 更新的滾動狀態。 SCROLL_STATE_IDLE 、 SCROLL_STATE_DRAGGING或SCROLL_STATE_SETTLING 。

第一個是當前滾動的recy,也就是說這個監聽器可以為多個recy服務,可以復用
第二個是滾動狀態,三個常量的意思分別是

// RecyclerView 當前未滾動public static final int SCROLL_STATE_IDLE = 0;//RecyclerView 當前正被外部輸入(例如用戶觸摸輸入)拖動public static final int SCROLL_STATE_DRAGGING = 1;// RecyclerView 當前正在動畫到最終位置,而不受外部控制。public static final int SCROLL_STATE_SETTLING = 2;

前兩個無非就是滾動和靜止,第三個就是當快速拖動時,手指離開了屏幕,但滾動由于源碼設定的慣性仍在滾動

onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy)

當 RecyclerView 滾動時調用的回調方法。 這將在滾動完成后調用。
如果在布局計算后可見項目范圍發生變化,也會調用此回調。 在這種情況下,dx 和 dy 將為 0。
參數:
recyclerView – 滾動的 RecyclerView。
dx – 水平滾動量。
dy – 垂直滾動量。

第二句話的意思是,recycler布局重新計算后,都會返回兩個0,比如剛進入activity
到這里想必思路已經出來了,只要知道最后一個item是否顯示就行

方法1:

通過布局管理器獲取到現在所顯示的item個數,第一個item的位置(Position),一共有多少個item
總數<= 第一個pos+屏幕顯示的item
代碼如下

//加載顯示,避免重復加載 boolean load = true;recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {/*** 當 RecyclerView 的滾動狀態改變時調用的回調方法。* 參數:* recyclerView – 滾動狀態已更改的 RecyclerView。* newState – 更新的滾動狀態。 SCROLL_STATE_IDLE 、 SCROLL_STATE_DRAGGING或SCROLL_STATE_SETTLING 。* */@Overridepublic void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {super.onScrollStateChanged(recyclerView, newState);}/*** 當 RecyclerView 滾動時調用的回調方法。 這將在滾動完成后調用。* 如果在布局計算后可見項目范圍發生變化,也會調用此回調。 在這種情況下,dx 和 dy 將為 0。* */@Overridepublic void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);//當dy為負時是往上 正才是往下if (dy > 0) {int visibleItemCount = layoutManager.getChildCount(); //得到顯示屏幕內的list數量int totalItemCount = layoutManager.getItemCount(); //得到list的總數量int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();//得到顯示屏內的第一個list的位置數positionif (load && (visibleItemCount + firstVisiblePosition) >= totalItemCount) {//添加數據,或者用網絡請求 //記住加載完成后需要 load = false 無論成功與否addRecyclerData();}}}});/*** 添加十條數據* */private void addRecyclerData(){for (int i=0;i<10;i++){adapter4.addData("0000");}load = true;}

方法2

在適配器里計算每個view的高度

public class RecyclerAdapter4 extends RecyclerView.Adapter<RecyclerAdapter4.Holder> {//適配器數據private List<String> list;private Context context;//獲取整個recycler里的所有item高度總和,必須要拉到底private int itemHeightSum = 0;//避免recycler的銷毀和恢復影響高度計算private ArrayList<Boolean> load;public RecyclerAdapter4(Context context) {this.context = context;list = new ArrayList<>();load= new ArrayList<>();}/*** 創建布局*/@NonNull@Overridepublic Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {//直接簡寫成一行 如果看不懂可以回看《初步使用》文章return new Holder(LayoutInflater.from(context).inflate(R.layout.recy_list3, parent, false));}@SuppressLint("SetTextI18n")@Overridepublic void onBindViewHolder(@NonNull Holder holder, int position) {//顯示pos對應的textviewholder.text.setText("這是第" + (position + 1) + "個ImageView -> ");//view.post是view渲染出來后執行,如果直接獲取高度是0holder.itemView.post(() -> {//load中第pos個計算過高度,不予計算if (load.get(position)){//只計算一次load.add(position,false);//自增高度itemHeightSum += holder.itemView.getHeight();}});}@Overridepublic int getItemCount() {return list.size();}/*** 添加數據*/public void addData(String str) {list.add(str);//新添加的需要計算 給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的每次復用,記錄下哪個沒有計算高度
滑到底時全部item都計算過
注意添加數據必須使用自己寫的addData方法,又或者必須在對應的位置load.add(true)

另外需要注意的是 item不能設置外邊距 否則高度會有出入
另外需要注意的是 item不能設置外邊距 否則高度會有出入
另外需要注意的是 item不能設置外邊距 否則高度會有出入

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() {//省略,代碼在上面的準備}/*** 監聽到底*/private void onBottom() {/*** 添加一個偵聽器,該偵聽器將收到滾動狀態或位置的任何更改的通知。* 添加偵聽器的組件在完成后應注意將其刪除。* 擁有視圖所有權的其他組件可能會調用clearOnScrollListeners()以刪除所有附加的偵聽器** 可以將 OnScrollListener 添加到 RecyclerView* 以在該 RecyclerView 上發生滾動事件時接收消息。* */recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {/*** 當 RecyclerView 的滾動狀態改變時調用的回調方法。* 參數:* recyclerView – 滾動狀態已更改的 RecyclerView。* newState – 更新的滾動狀態。 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的實際高度 + 滑動的距離Log.i(TAG, "y : " + y);//判斷recycler是否滑到底 //到底時recycler的實際高度 + 滑動的距離 == 全部item的高度if (y >= adapter4.getItemHeightSum() && load) {load = false;//避免重復刷新Toast.makeText(RecyclerActivity.this,"刷新",Toast.LENGTH_SHORT).show();addRecyclerData();}Log.i(TAG, "靜止");case RecyclerView.SCROLL_STATE_DRAGGING:Log.i(TAG, "滑動");case RecyclerView.SCROLL_STATE_SETTLING:Log.i(TAG, "慣性");}}/*** 當 RecyclerView 滾動時調用的回調方法。 這將在滾動完成后調用。* 如果在布局計算后可見項目范圍發生變化,也會調用此回調。 在這種情況下,dx 和 dy 將為 0。* */@Overridepublic void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);//添加滑動距離 此次不必限制 往上減往下加y += dy;}});}/*** 當窗口獲得焦點時* */@Overridepublic void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);//獲取recycler的高度y = recyclerView.getHeight();}/*** 添加十條數據* */private void addRecyclerData(){for (int i=0;i<10;i++){adapter4.addData("0000");}load = true;} }

效果圖

方法3

使用canScrollVertically
在onScrollStateChanged中添加如下代碼

@Overridepublic void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {super.onScrollStateChanged(recyclerView, newState);/*** 檢查此視圖是否可以在某個方向垂直滾動。* 參數:* 方向 - 檢查向上滾動為負,檢查向下滾動為正。* 返回:* 如果此視圖可以沿指定方向滾動,則為 true,否則為 false* */Log.i(TAG, "可以向上滑"+recyclerView.canScrollVertically(-1));Log.i(TAG, "可以向下滑"+recyclerView.canScrollVertically(1));//當不可以向下滑時到底 同時沒有在加載if(!load && !recyclerView.canScrollVertically(1)){load = true;//添加數據addRecyclerData();}}

結尾

沒有花里胡哨的動畫或者回彈加載
簡單的監聽到底部,如果需要可以根據上篇的添加布局實現加載動畫
github上也有許多開源的上拉加載
本文僅限原理分析和實現方法
本來想加下拉刷新的講解,字數過多,只能等下篇

最后
對本文有任何意見或疑問,或者認為其中說法有誤,歡迎在評論區留言!!!
轉載請注明出處!!

總結

以上是生活随笔為你收集整理的RecyclerView进阶使用(上拉加载)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。