Markdown版本筆記 | 我的GitHub首頁 | 我的博客 | 我的微信 | 我的郵箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
RecyclerView 判斷滑到底部 頂部 預加載 更多 分頁 MD
目錄
目錄
項目中的案例【預加載】
項目中的另一個案例
利用 lastVisibleItemPosition 判斷【不靠譜】
利用 computeVerticalScrollRange 等判斷【不靠譜】
利用 canScrollVertically(direction) 判斷【比較靠譜】
利用 LinearLayoutManager 來判斷【垃圾】
項目中的案例【預加載】
項目中的另一個案例
利用 lastVisibleItemPosition 判斷【不靠譜】
利用 computeVerticalScrollRange 等判斷【不靠譜】
利用 canScrollVertically(direction) 判斷【比較靠譜】
利用 LinearLayoutManager 來判斷【垃圾】
判斷RecyclerView到達底部的幾種方法
項目中的案例【預加載】
mRvChat.addOnScrollListener(new RecyclerView.OnScrollListener() {
private int minLeftItemCount=10;//剩余多少條時開始加載更多
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int itemCount = layoutManager.getItemCount();
int lastPosition = layoutManager.findLastCompletelyVisibleItemPosition();
XLog.tag("bqt3").i("【總數】" + itemCount + "【位置】" + lastPosition);
if (lastPosition == layoutManager.getItemCount() - 1) {//容錯處理,保證滑到最后一條時一定可以加載更多
this.onLoadMore();
} else {
if (itemCount > minLeftItemCount) {
if (lastPosition == itemCount - minLeftItemCount) {
//一定要意識到,onScrolled方法並不是一直被回調的,估計最多一秒鍾幾十次
//所以當此條件滿足時,可能並沒有回調onScrolled方法,也就不會調用onLoadMore方法
//所以一定要想辦法彌補這隱藏的bug,最簡單的方式就是當滑到最后一條時一定可以加載更多
this.onLoadMore();
}
} else {//(第一次進入時)如果總數特別少,直接加載更多
this.onLoadMore();
}
}
}
}
private void onLoadMore() {
if (canLoadMore) {
canLoadMore = false;
ChatReqHelper.requestGroupHis(groupId, ((ChatModel) mGroupChats.get(mGroupChats.size() - 1)).getMsgId());
XLog.tag("bqt3").i("【加載更多數據】");
}
}
});
項目中的另一個案例
rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) rv.getLayoutManager();
int[] positions = layoutManager.findLastVisibleItemPositions(null);
if (positions != null && positions.length > 0) {
for (int position : positions) {
if (position >= mDatas.size() - layoutManager.getSpanCount() || !rv.canScrollVertically(1)) {//滑到底部了
if (canLoadMore) {
XLog.tag("bqt_red").i("加載更多 "+position+" "+rv.canScrollVertically(1));
canLoadMore = false;
doRequest();
}
break;
}
}
}
}
});
利用 lastVisibleItemPosition 判斷【不靠譜】
簡單判斷
public static boolean isVisBottom(RecyclerView recyclerView){
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); //屏幕中最后一個可見子項的position
int visibleItemCount = layoutManager.getChildCount(); //當前屏幕所看到的子項個數
int totalItemCount = layoutManager.getItemCount(); //當前RecyclerView的所有子項個數
int state = recyclerView.getScrollState(); //RecyclerView的滑動狀態
if(visibleItemCount > 0 && lastVisibleItemPosition == totalItemCount - 1 && state == recyclerView.SCROLL_STATE_IDLE){
return true;
}else {
return false;
}
}
當屏幕中最后一個子項 lastVisibleItemPosition 等於所有子項個數 totalItemCount - 1,那么RecyclerView就到達了底部。
但是,如果 totalItemCount 等於1,並且這個item的高度比屏幕還要高時,我們可以發現這個item沒完全顯示出來就已經被判斷為拉到底部。
利用 computeVerticalScrollRange 等判斷【不靠譜】
這種方法原理其實很簡單,而且也是View自帶的方法
public static boolean isSlideToBottom(RecyclerView recyclerView) {
return recyclerView != null
&& recyclerView.computeVerticalScrollExtent()//當前屏幕顯示區域的高度
+ recyclerView.computeVerticalScrollOffset()//當前屏幕之前滑過的距離
>= recyclerView.computeVerticalScrollRange();//整個View控件的高度
}
這種方法經過測試,暫時還沒發現有bug,而且它用的是View自帶的方法,所以個人覺得比較靠譜。
利用 canScrollVertically(direction) 判斷【比較靠譜】
這種方法更簡單,就通過簡單的調用方法,就可以得到你想要的結果。
這種方法與第二種方法其實是同一種方法,我們看看 canScrollVertically 的源碼:
/**
* Check if this view can be scrolled vertically in a certain direction.
*
* @param direction Negative to check scrolling up, positive to check scrolling down.
* @return true if this view can be scrolled in the specified direction, false otherwise.
*/
public boolean canScrollVertically(int direction) {
final int offset = computeVerticalScrollOffset();
final int range = computeVerticalScrollRange() - computeVerticalScrollExtent();
if (range == 0) return false;
if (direction < 0) {
return offset > 0;
} else {
return offset < range - 1;
}
}
canScrollVertically(1)的值表示是否能向上滾動,true表示能滾動,false表示已經滾動到底部
canScrollVertically(-1)的值表示是否能向下滾動,true表示能滾動,false表示已經滾動到頂部
利用 LinearLayoutManager 來判斷【垃圾】
這種方法其實是比較呆板的,就是利用LinearLayoutManager的幾個方法算出已經滑過的子項的距離、屏幕的高度、RecyclerView的總高度,最后將高度作比較。
- 算出一個子項的高度
public static int getItemHeight(RecyclerView recyclerView) {
int itemHeight = 0;
View child = null;
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int firstPos = layoutManager.findFirstCompletelyVisibleItemPosition();
int lastPos = layoutManager.findLastCompletelyVisibleItemPosition();
child = layoutManager.findViewByPosition(lastPos);
if (child != null) {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
itemHeight = child.getHeight() + params.topMargin + params.bottomMargin;
}
return itemHeight;
}
- 算出滑過的子項的總距離
public static int getLinearTotalHeight(RecyclerView recyclerView) {
int totalHeight = 0;
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
View child = layoutManager.findViewByPosition(layoutManager.findFirstVisibleItemPosition());
int headerCildHeight = getHeaderHeight(recyclerView);
if (child != null) {
int itemHeight = getItemHeight(recyclerView);
int childCount = layoutManager.getItemCount();
totalHeight = headerCildHeight + (childCount - 1) * itemHeight;
}
return totalHeight;
}
- 算出所有子項的總高度
public static boolean isLinearBottom(RecyclerView recyclerView) {
boolean isBottom = true;
int scrollY = getLinearScrollY(recyclerView);
int totalHeight = getLinearTotalHeight(recyclerView);
int height = recyclerView.getHeight();
// Log.e("height","scrollY " + scrollY + " totalHeight " + totalHeight + " recyclerHeight " + height);
if (scrollY + height < totalHeight) {
isBottom = false;
}
return isBottom;
}
- 其他邏輯
public static int getHeaderHeight(RecyclerView recyclerView) {
int headerCildHeight = 0;
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int firstHeaderPos = layoutManager.findFirstCompletelyVisibleItemPosition();
View headerCild = layoutManager.findViewByPosition(firstHeaderPos);
if (headerCild != null) {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) headerCild.getLayoutParams();
headerCildHeight = headerCild.getHeight() + params.topMargin + params.bottomMargin;
}
return headerCildHeight;
}
public static int getLinearScrollY(RecyclerView recyclerView) {
int scrollY = 0;
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int headerCildHeight = getHeaderHeight(recyclerView);
int firstPos = layoutManager.findFirstVisibleItemPosition();
View child = layoutManager.findViewByPosition(firstPos);
int itemHeight = getItemHeight(recyclerView);
if (child != null) {
int firstItemBottom = layoutManager.getDecoratedBottom(child);
scrollY = headerCildHeight + itemHeight * firstPos - firstItemBottom;
if (scrollY < 0) {
scrollY = 0;
}
}
return scrollY;
}
雖然這種方法看上去比較呆板的同時考慮不很周全,但這種方法可以對RecylerView的LinearLayoutManager有深一步的理解!
2017.06.23