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
Adapter部分
RecyclerAdapter4.java
Activity布局部分
activity_recycler.xml
item布局部分
recy_list3.xml
效果如圖
上拉加載
上拉,手指上滑,直到出現第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服務,可以復用
第二個是滾動狀態,三個常量的意思分別是
前兩個無非就是滾動和靜止,第三個就是當快速拖動時,手指離開了屏幕,但滾動由于源碼設定的慣性仍在滾動
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
代碼如下
方法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中添加如下代碼
結尾
沒有花里胡哨的動畫或者回彈加載
簡單的監聽到底部,如果需要可以根據上篇的添加布局實現加載動畫
github上也有許多開源的上拉加載
本文僅限原理分析和實現方法
本來想加下拉刷新的講解,字數過多,只能等下篇
最后
對本文有任何意見或疑問,或者認為其中說法有誤,歡迎在評論區留言!!!
轉載請注明出處!!
總結
以上是生活随笔為你收集整理的RecyclerView进阶使用(上拉加载)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: KaggleM5 Forecasting
- 下一篇: 一个可以免费去除图片背景的网站