Android代碼實現(xiàn)AdapterViews和RecyclerView無限滾動
應用的一個共同的特點就是當用戶歡動時自動加載更多的內(nèi)容,這是通過用戶滑動觸發(fā)一定的閾值時發(fā)送數(shù)據(jù)請求實現(xiàn)的。
相同的是:信息實現(xiàn)滑動的效果需要定義在列表中最后一個可見項,和某些類型的閾值以便于開始在最后一項到達之前開始抓取數(shù)據(jù),實現(xiàn)無限的滾動。
實現(xiàn)無限滾動的現(xiàn)象的重要之處就在于在用戶滑動到最低端之前就行數(shù)據(jù)的獲取,所以需要加上一個閾值來幫助實現(xiàn)獲取數(shù)據(jù)的預期。
使用ListView和GridView實現(xiàn)
每個AdapterView 例如ListView 和GridView 當用戶開始進行滾動操作時候都會觸發(fā)OnScrollListener .使用這個系統(tǒng)我們就可以定義一個基本的EndlessScrollListener ,通過創(chuàng)造繼承OnScrollListener 的類來支持大多數(shù)情況下的使用。
package com.codepath.customadapter;
import android.widget.AbsListView;
/**
* Created by Administrator on 2016/7/11.
*/
public abstract class EndlessScrollListener implements AbsListView.OnScrollListener {
//在你滑動項下最少為多少時開始加載數(shù)據(jù)
private int visibleThreshold = 5;
//已經(jīng)加載數(shù)據(jù)的當前頁碼
private int currentPage = 0;
//上一次加載數(shù)據(jù)后數(shù)據(jù)庫的數(shù)據(jù)量
private int previousTotalItemCount = 0;
//我們是否在等待最后一組數(shù)據(jù)的加載
private boolean loading = true;
//設置開始頁的下標
private int startingPageIndex = 0;
public EndlessScrollListener() {
}
public EndlessScrollListener(int visibleThreshold) {
this.visibleThreshold = visibleThreshold;
}
public EndlessScrollListener(int visibleThreshold, int startingPageIndex) {
this.visibleThreshold = visibleThreshold;
this.startingPageIndex = startingPageIndex;
}
//這個方法可能會在滑動調(diào)用很多次,所以在設計時要保持謹慎
//我們需要一些有用的參數(shù)來幫助我們,當我們需要加載更多數(shù)據(jù)的時候
//但是我們首先要檢查是否我們在等待先前的加載結(jié)束
//onScroll()當列表或網(wǎng)格視圖被滾動后將會調(diào)用,參數(shù)一:報告狀態(tài)的視圖參數(shù)二:第一個可以看見的項的下標,參數(shù)三:可見項的數(shù)量參數(shù)四:listAdapter中所有的項數(shù)
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//如果總項數(shù)為0,而且先前沒有項,那么這個列表是無效的應該被設定為初始狀態(tài)
if (totalItemCount < previousTotalItemCount) {
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0) {this.loading = true;}
}
//如果仍在加載中我們可以檢查一下數(shù)據(jù)集合是否改變了,如果改變的話那就是已經(jīng)完成了loading需要更新當前
//頁數(shù)和數(shù)據(jù)總量
if (loading && (totalItemCount > previousTotalItemCount)) {
loading = false;
previousTotalItemCount = totalItemCount;
currentPage++;
}
//如果當前沒有加載,我們需要檢查當前是否達到了閾值,如果是的話我們需要
//加載更多的數(shù)據(jù),執(zhí)行onLoadMore
if (!loading && (firstVisibleItem + visibleItemCount + visibleThreshold) >= totalItemCount) {
loading = onLoadMore(currentPage + 1, totalItemCount);
}
}
//定義實際加載數(shù)據(jù)的過程,如果數(shù)據(jù)加載完成返回false,如果正在加載返回true;
public abstract boolean onLoadMore(int page, int totalItemCount);
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
//不采取動作
}
}
要注意的是這是一個抽象的類,為了要使用這些,必須繼承這個基本的類并且實現(xiàn)onLoadMore()方法實際的獲取數(shù)據(jù), 我們在一個活動中定義一個匿名的類來繼承EndlessScrollListener然后將其連接AdapterView上
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstance) {
//向平常一樣
ListView lvItems = (ListView) findViewById(R.id.lvItens);
//將監(jiān)聽器綁定到上面
lvItems.setOnScrollListener(new EndlessScrollListener() {
@Override
public boolean onLoadMore(int page, int totalItemsCount) {
// 當新數(shù)據(jù)需要綁定到列表上的時候觸發(fā)
// 加載數(shù)據(jù)需要的代碼Add whatever code is needed to append new items to your AdapterView
customLoadMoreDataFromApi(page);
// or customLoadMoreDataFromApi(totalItemsCount);
return true; //數(shù)據(jù)加載中為true,不然為false; ONLY if more data is actually being loaded; false otherwise.
}
});
}
//加載更多的數(shù)據(jù)
public void customLoadMoreDataFromApi(int offset) {
//這個方法通常會發(fā)起一些網(wǎng)絡請求,然后向適配器添加更多的數(shù)據(jù)
//將偏移量數(shù)據(jù)作為參數(shù)附在請求里來獲得一個數(shù)據(jù)的分頁
//解析API返回的值并且獲得新的對象構(gòu)建適配器
}
}
現(xiàn)在當用戶滑動并且觸發(fā)閾值時會自動觸發(fā)onloadMore() 方法,而且監(jiān)聽器給予了對于頁數(shù)和數(shù)據(jù)總量的訪問權(quán)限。
實現(xiàn)RecyclerView的無限滑動
我們可以使用相同的方法來定義一個接口EndlessRecyclerViewScrollListener 然后定義一個onLoadMore() 的方法來進行實現(xiàn)。由于LayoutManager負責項的生成和滑動的管理,我們需要一個LayoutManage的實例來收集必要的信息。
實現(xiàn)必要的分頁需要這樣的步驟:
1).直接復制EndlessRecyclerViewScrollListener.java
2).調(diào)用addOnScrollListener(...) 在RecyclerView 中來實現(xiàn)無限的分頁,傳遞EndlessRecyclerViewScrollListener的實例來實現(xiàn)onLoadMore 方法來決定什么時候來加載新的數(shù)據(jù)
3).在onLoadMore 方法中通過發(fā)送網(wǎng)絡請求或者從源數(shù)據(jù)加載來獲得更多item。
protected void onCreate(Bundle savedInstanceState) {
// Configure the RecyclerView獲得RecylerView的實例
RecyclerView rvItems = (RecyclerView) findViewById(R.id.rvContacts);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
// Add the scroll listener
rvItems.addOnScrollListener(new EndlessRecyclerViewScrollListener(linearLayoutManager) {
@Override
public void onLoadMore(int page, int totalItemsCount) {
// Triggered only when new data needs to be appended to the list
// Add whatever code is needed to append new items to the bottom of the list
customLoadMoreDataFromApi(page);
}
});
}
// Append more data into the adapter
// This method probably sends out a network request and appends new data items to your adapter.
public void customLoadMoreDataFromApi(int page) {
// Send an API request to retrieve appropriate data using the offset value as a parameter.
// --> Deserialize API response and then construct new objects to append to the adapter
// --> Notify the adapter of the changes
}
}
EndlessRecyclerView
public abstract class EndlessRecyclerViewScrollListener extends RecyclerView.OnScrollListener {
// The minimum amount of items to have below your current scroll position
// before loading more.
private int visibleThreshold = 5;
// The current offset index of data you have loaded
private int currentPage = 0;
// The total number of items in the dataset after the last load
private int previousTotalItemCount = 0;
// True if we are still waiting for the last set of data to load.
private boolean loading = true;
// Sets the starting page index
private int startingPageIndex = 0;
RecyclerView.LayoutManager mLayoutManager;
public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
}
public EndlessRecyclerViewScrollListener(GridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public int getLastVisibleItem(int[] lastVisibleItemPositions) {
int maxSize = 0;
for (int i = 0; i < lastVisibleItemPositions.length; i++) {
if (i == 0) {
maxSize = lastVisibleItemPositions[i];
}
else if (lastVisibleItemPositions[i] > maxSize) {
maxSize = lastVisibleItemPositions[i];
}
}
return maxSize;
}
// This happens many times a second during a scroll, so be wary of the code you place here.
// We are given a few useful parameters to help us work out if we need to load some more data,
// but first we check if we are waiting for the previous load to finish.
@Override
public void onScrolled(RecyclerView view, int dx, int dy) {
int lastVisibleItemPosition = 0;
int totalItemCount = mLayoutManager.getItemCount();
if (mLayoutManager instanceof StaggeredGridLayoutManager) {
int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);
// get maximum element within the list
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
} else if (mLayoutManager instanceof LinearLayoutManager) {
lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();
} else if (mLayoutManager instanceof GridLayoutManager) {
lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition();
}
// If the total item count is zero and the previous isn't, assume the
// list is invalidated and should be reset back to initial state
if (totalItemCount < previousTotalItemCount) {
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0) {
this.loading = true;
}
}
// If it's still loading, we check to see if the dataset count has
// changed, if so we conclude it has finished loading and update the current page
// number and total item count.
if (loading && (totalItemCount > previousTotalItemCount)) {
loading = false;
previousTotalItemCount = totalItemCount;
}
// If it isn't currently loading, we check to see if we have breached
// the visibleThreshold and need to reload more data.
// If we do need to reload some more data, we execute onLoadMore to fetch the data.
// threshold should reflect how many total columns there are too
if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) {
currentPage++;
onLoadMore(currentPage, totalItemCount);
loading = true;
}
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int page, int totalItemsCount);
}
注意問題:
1.對于ListView,確定將綁定監(jiān)聽器的步驟放在onCreate()的方法中
2.為可加可靠的進行分頁,需要確定在向列表中添加新數(shù)據(jù)的時候先清理適配器中的數(shù)據(jù)
對于RecyclerView來說在通知適配器時推薦更細致的更新。
3.對于RecyclerView來說確保在清除列表中的數(shù)據(jù)的時候迅速的通知適配器內(nèi)容更新了,以便于可以觸發(fā)新的onScroll事件,重置自己
展示進度條
為了在底部展示進度條證明ListView正在加載。我們可以在Adapter中進行設置,我們可以定義兩類,可以是進度條類型或者是文本表明達到了最底行,參考:http://guides.codepath.com/android/Endless-Scrolling-with-AdapterViews-and-RecyclerView
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android 中 viewpager 滑動指示器的實例代碼
本文通過實例代碼給大家介紹了android 中 viewpager 滑動指示器,代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-12-12
Android通過自定義ImageView控件實現(xiàn)圖片的縮放和拖動的實現(xiàn)代碼
通過自定義ImageView控件,在xml布局里面調(diào)用自定的組件實現(xiàn)圖片的縮放。下面給大家分享實現(xiàn)代碼,感興趣的朋友一起看看吧2016-10-10
Flutter使用JsBridge方式處理Webview與H5通信的方法
這篇文章主要介紹了Flutter使用JsBridge方式處理Webview與H5通信的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-04-04
Android自定義收音機搜臺控件RadioRulerView
這篇文章主要為大家詳細介紹了Android自定義收音機搜臺控件RadioRulerView的相關代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
Android_UI 仿QQ側(cè)滑菜單效果的實現(xiàn)
相信大家對QQ側(cè)滑菜單的效果已經(jīng)不陌生了吧,側(cè)滑進入個人頭像一側(cè),進行對頭像的更改,我的收藏,QQ錢包,我的文件等一系列的操作,下面小編給大家分享Android_UI 仿QQ側(cè)滑菜單效果的實現(xiàn),一起看看吧2017-04-04

