android教你打造獨一無二的上拉下拉刷新加載框架
其實早在去年七月,群里小伙伴就有讓我共享這個。但我當時絕的技術不純熟。代碼有bug什么的。沒有寫出來?,F(xiàn)在感覺整理的差不多了。就寫出來讓大家看看,有問題一起討論解決。
說到刷新加載,我們第一個想到啥,對了就是swiperefreshlayout,還有什么SuperSwiperefreshlayout,XRecyclerView等等。反正老多了,我還是之前那句話,不管用什么,我們需要知道他的原理。
打造框架開始
對于刷新加載的實現(xiàn),你們第一個想到的是什么?是用swiperefresh然后在recyclerview底部加一個不同type?還是用事件攔截呢?那必須是事件攔截啊,雖然現(xiàn)在swiperefreshlayout很火,基本很多app都能看到他。但是遇到那種坑比公司說刷新要用自己公司logo你也沒轍。對把。。好了,感覺得罪了好多公司,不管他,我們繼續(xù)。
我們先看下我們的效果圖:

老鐵,沒毛病。下面我介紹如何實現(xiàn)的。
下拉刷新
首先我們給出如下幾個參數(shù),后面要用:
private NestedScrollingParentHelper helper = null; private boolean IsRefresh = true; private boolean IsLoad = true; //滑動的總距離 private int totalY = 0; private LinearLayout headerLayout = null; private MyRecyclerView myRecyclerView = null; private LinearLayout footerLayout = null;
既然是刷新,我們的滾動肯定是在父view之前的。所以我們需要在onNestedPreScroll這個方法里面寫上我們所需要改動的x,y值。
我們需要用父view去攔截它。
我們需要判斷dy的值是否大于0,因為大于0是刷新操作,小于0是加載操作。然后我們需要判斷recyclerview是否是縱向的而不是橫向的。
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
if (IsRefresh) {
if (dy > 0) {
if (myRecyclerView.isOrientation(0)) {
totalY += dy;
if ((totalY / 2) <= 0) {
scrollTo(0, totalY / 2);
consumed[1] = dy;
} else {
scrollTo(0, 0);
consumed[1] = 0;
}
}
return;
}
}
上拉加載
上面我也說了onNestedPreScroll這個方法中判斷dy<0才是加載操作。所以綜上所述,代碼變成了這樣:
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
if (totalY < 0 && myRecyclerView.isOrientation(0) || totalY > 0 && myRecyclerView.isOrientation(1)) {
isfling = true;
}
if (IsRefresh) {
if (dy > 0) {
if (myRecyclerView.isOrientation(0)) {
totalY += dy;
if ((totalY / 2) <= 0) {
scrollTo(0, totalY / 2);
consumed[1] = dy;
} else {
scrollTo(0, 0);
consumed[1] = 0;
}
}
return;
}
}
if (IsLoad) {
if (dy < 0) {
if (myRecyclerView.isOrientation(1)) {
totalY += dy;
if ((totalY / 2) >= 0) {
scrollTo(0, totalY / 2);
consumed[1] = dy;
} else {
scrollTo(0, 0);
consumed[1] = 0;
}
}
return;
}
}
}
最后我們需要在子view滑動結束后,實行如下操作:
//子view滑動結束調用
//dyUnconsumed < 0 向下滾
//dyUnconsumed > 0 向上滾
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
if (dyUnconsumed != 0) {
totalY += dyUnconsumed;
scrollTo(0, totalY / 2);
}
}
其實最主要的兩個方法已經解決了,其他到沒什么了,這邊,我把nestedscrolling的8個接口的功能和自定義recyclerview放出來。已變大家參考。希望大家都能實現(xiàn)自己的刷新加載。告別swiperefreshlayout。
添加header和footer
這里我們參考listview自帶的addheaderview和addfooterview。代碼如下:
public void addHeaderView(View headerView, int headerHeight) {
this.headerLayout.removeAllViews();
this.headerLayout.addView(headerView);
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, headerHeight);
layoutParams.topMargin = -headerHeight;
this.headerLayout.setLayoutParams(layoutParams);
}
public void addFooterView(View footerView, int footerHeight) {
this.footerLayout.removeAllViews();
this.footerLayout.addView(footerView);
this.footerLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, footerHeight));
}
幾個接口的實現(xiàn)
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
return true;
}
public void onNestedScrollAccepted(View child, View target, int axes) {
helper.onNestedScrollAccepted(child, target, axes);
}
//父view攔截子view的滾動
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
if (totalY < 0 && myRecyclerView.isOrientation(0) || totalY > 0 && myRecyclerView.isOrientation(1)) {
isfling = true;
}
if (IsRefresh) {
if (dy > 0) {
if (myRecyclerView.isOrientation(0)) {
totalY += dy;
if ((totalY / 2) <= 0) {
scrollTo(0, totalY / 2);
consumed[1] = dy;
} else {
scrollTo(0, 0);
consumed[1] = 0;
}
}
return;
}
}
if (IsLoad) {
if (dy < 0) {
if (myRecyclerView.isOrientation(1)) {
totalY += dy;
if ((totalY / 2) >= 0) {
scrollTo(0, totalY / 2);
consumed[1] = dy;
} else {
scrollTo(0, 0);
consumed[1] = 0;
}
}
return;
}
}
}
//子view滑動結束調用
//dyUnconsumed < 0 向下滾
//dyUnconsumed > 0 向上滾
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
if (dyUnconsumed != 0) {
totalY += dyUnconsumed;
scrollTo(0, totalY / 2);
}
}
public void onStopNestedScroll(View child) {
helper.onStopNestedScroll(child);
if (onTouchUpListener != null) {
isfling = false;
onTouchUpListener.touchUp();
}
}
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
return isfling;
}
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
return isfling;
}
public int getNestedScrollAxes() {
return helper.getNestedScrollAxes();
}
自定義recyclerview
既然是自己寫的刷新加載框架,總不能還有自定義layout中在放個recyclerview。多麻煩,自定義一個,直接放在里面,然后分別放個header和footer 就沒必要每次有頁面用到刷新都要寫一個布局。3個布局解決整個項目的刷新和加載。話不多說,代碼如下:
private class MyRecyclerView extends RecyclerView {
private StaggeredGridLayoutManager staggeredGridLayoutManager = null;
private LinearLayoutManager linearLayoutManager = null;
private GridLayoutManager gridLayoutManager = null;
private boolean isScrollLoad = false;
private boolean isScrollRefresh = false;
public MyRecyclerView(Context context) {
super(context);
setVerticalFadingEdgeEnabled(false);
setHorizontalFadingEdgeEnabled(false);
setVerticalScrollBarEnabled(false);
setHorizontalScrollBarEnabled(false);
setOverScrollMode(OVER_SCROLL_NEVER);
setItemAnimator(new DefaultItemAnimator());
}
private void setMyLayoutManager(LayoutManager layoutManager) {
if (layoutManager instanceof StaggeredGridLayoutManager) {
staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
} else if (layoutManager instanceof GridLayoutManager) {
gridLayoutManager = (GridLayoutManager) layoutManager;
} else if (layoutManager instanceof LinearLayoutManager) {
linearLayoutManager = (LinearLayoutManager) layoutManager;
}
setLayoutManager(layoutManager);
if (!isVertical()) {
throw new NullPointerException("vertical!");
}
}
private boolean isOrientation(int orientation) {//orientation,0代表向下,1代表向上
if (orientation == 0)
return isCanPullDown();
else if (orientation == 1)
return isCanPullUp();
return false;
}
private boolean isCanPullDown() {
return !canScrollVertically(-1);
}
private boolean isCanPullUp() {
return !canScrollVertically(1);
}
// private int scrollLoad() {
// int lastItem = 0;
// int itemCount = 0;
// int spanCount = 1;
// if (staggeredGridLayoutManager != null) {
// lastItem = staggeredGridLayoutManager.findLastVisibleItemPositions(null)[0];
// itemCount = staggeredGridLayoutManager.getItemCount();
// spanCount = staggeredGridLayoutManager.getSpanCount();
// } else if (linearLayoutManager != null) {
// lastItem = linearLayoutManager.findLastVisibleItemPosition();
// itemCount = linearLayoutManager.getItemCount();
// spanCount = 1;
// } else if (gridLayoutManager != null) {
// lastItem = gridLayoutManager.findLastVisibleItemPosition();
// itemCount = gridLayoutManager.getItemCount();
// spanCount = gridLayoutManager.getSpanCount();
// }
// return ((itemCount - 1) / spanCount + 1) - (lastItem / spanCount + 1);
// }
private boolean isVertical() {
if (staggeredGridLayoutManager != null)
return staggeredGridLayoutManager.getOrientation() == StaggeredGridLayoutManager.VERTICAL;
else if (linearLayoutManager != null)
return linearLayoutManager.getOrientation() == LinearLayoutManager.VERTICAL;
else if (gridLayoutManager != null)
return gridLayoutManager.getOrientation() == GridLayoutManager.VERTICAL;
return false;
}
// public void onScrolled(int dx, int dy) {
// if (dy > 0 && !isScrollLoad) {
// if (oLior != null) {
// onScrollListener.scrollLoad(sc````````
`
``
llLoad());//傳遞滾動到倒數(shù)第幾行
// }
// }
// }
}
這樣我們變實現(xiàn)了自己的刷新加載框架,代碼我已上傳:SWPullRecyclerLayout_jb51.rar
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android編程開發(fā)之在Canvas中利用Path繪制基本圖形(圓形,矩形,橢圓,三角形等)
這篇文章主要介紹了Android編程開發(fā)之在Canvas中利用Path繪制基本圖形的方法,涉及Android基本的圖形繪制技巧,結合實例分析了繪制圓形,矩形,橢圓,三角形等基本圖形的實現(xiàn)方法,需要的朋友可以參考下2016-01-01
android輕量級無侵入式管理數(shù)據(jù)庫自動升級組件
這篇文章主要為大家介紹了android輕量級無侵入式管理數(shù)據(jù)庫自動升級組件詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02
android實現(xiàn)定時拍照并發(fā)送微博功能
這篇文章主要為大家詳細介紹了android實現(xiàn)定時拍照并發(fā)送微博功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06
Android控件Tween動畫(補間動畫)實現(xiàn)方法示例
這篇文章主要介紹了Android控件Tween動畫(補間動畫)實現(xiàn)方法,結合具體實例形式分析了Android補間動畫的原理、功能實現(xiàn)與布局相關操作技巧,需要的朋友可以參考下2017-08-08
android中RecycleView添加下滑到底部的監(jiān)聽示例
本篇文章主要介紹了android中RecycleView添加下滑到底部的監(jiān)聽示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-03-03
詳談Android中onTouch與onClick事件的關系(必看)
下面小編就為大家?guī)硪黄斦凙ndroid中onTouch與onClick事件的關系(必看)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-03-03

