RecyclerView的下拉刷新需要自己封裝,其實是RecyclerView添加頭部之后的處理邏輯的編輯。所以我們繼承自添加頭部和底部的RecyclerView開始封裝。
一、添加頭部
處理下拉刷新吁恍,同時考慮刷新列表的不同風格樣式,確保每個項目都能用银受, 所以我們不能直接添加View践盼,需要利用輔助類鸦采。
public void addRefreshViewCreator(RefreshViewCreator refreshCreator) {
this.mRefreshCreator = refreshCreator;
addRefreshView();
}
其中輔助類提供給外界的方法
public abstract class RefreshViewCreator {
/**
* 獲取下拉刷新的View
*
* @param context 上下文
* @param parent RecyclerView
*/
public abstract View getRefreshView(Context context, ViewGroup parent);
/**
* 正在下拉
* @param currentDragHeight 當前拖動的高度
* @param refreshViewHeight 總的刷新高度
* @param currentRefreshStatus 當前狀態(tài)
*/
public abstract void onPull(int currentDragHeight, int refreshViewHeight, int currentRefreshStatus);
/**
* 正在刷新中
*/
public abstract void onRefreshing();
/**
* 停止刷新
*/
public abstract void onStopRefresh();
}
添加頭部的方法:
/**
* 添加頭部的刷新View
*/
private void addRefreshView() {
RecyclerView.Adapter adapter = getAdapter();
if (adapter != null && mRefreshCreator != null) {
// 添加頭部的刷新View
View refreshView = mRefreshCreator.getRefreshView(getContext(), this);
if (refreshView != null) {
addHeaderView(refreshView);
this.mRefreshView = refreshView;
}
}
}
二宾巍、重寫dispatchTouchEvent()方法
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// 記錄手指按下的位置 ,之所以寫在dispatchTouchEvent那是因為如果我們處理了條目點擊事件,
// 那么就不會進入onTouchEvent里面渔伯,所以只能在這里獲取
mFingerDownY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_UP:
if (mCurrentDrag) {
restoreRefreshView();
}
break;
}
return super.dispatchTouchEvent(ev);
}
restoreRefreshView()方法
/**
* 重置當前刷新狀態(tài)狀態(tài)
*/
private void restoreRefreshView() {
int currentTopMargin = ((MarginLayoutParams) mRefreshView.getLayoutParams()).topMargin;
int finalTopMargin = -mRefreshViewHeight + 1;
if (mCurrentRefreshStatus == REFRESH_STATUS_LOOSEN_REFRESHING) {
finalTopMargin = 0;
mCurrentRefreshStatus = REFRESH_STATUS_REFRESHING;
if (mRefreshCreator != null) {
mRefreshCreator.onRefreshing();
}
if (mListener != null) {
mListener.onRefresh();
}
}
int distance = currentTopMargin - finalTopMargin;
// 回彈到指定位置
ValueAnimator animator = ObjectAnimator.ofFloat(currentTopMargin, finalTopMargin).setDuration(distance);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentTopMargin = (float) animation.getAnimatedValue();
setRefreshViewMarginTop((int) currentTopMargin);
}
});
animator.start();
mCurrentDrag = false;
}
三顶霞、重寫onTouchEvent()方法
@Override
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
// 如果是在最頂部才處理,否則不需要處理
if (canScrollUp() || mCurrentRefreshStatus == REFRESH_STATUS_REFRESHING
|| mRefreshView == null || mRefreshCreator == null) {
// 如果沒有到達最頂端,也就是說還可以向上滾動就什么都不處理
return super.onTouchEvent(e);
}
// 解決下拉刷新自動滾動問題
if (mCurrentDrag) {
scrollToPosition(0);
}
// 獲取手指觸摸拖拽的距離
int distanceY = (int) ((e.getRawY() - mFingerDownY) * mDragIndex);
// 如果是已經(jīng)到達頭部选浑,并且不斷的向下拉蓝厌,那么不斷的改變refreshView的marginTop的值
if (distanceY > 0) {
int marginTop = distanceY - mRefreshViewHeight;
setRefreshViewMarginTop(marginTop);
updateRefreshStatus(distanceY);
mCurrentDrag = true;
return false;
}
break;
}
return super.onTouchEvent(e);
}
/**
* 設置刷新View的marginTop
*/
private void setRefreshViewMarginTop(int marginTop) {
MarginLayoutParams params = (MarginLayoutParams) mRefreshView.getLayoutParams();
if (marginTop < -mRefreshViewHeight + 1) {
marginTop = -mRefreshViewHeight + 1;
}
params.topMargin = marginTop;
mRefreshView.setLayoutParams(params);
}
/**
* 更新刷新的狀態(tài)
*/
private void updateRefreshStatus(int distanceY) {
if (distanceY <= 0) {
mCurrentRefreshStatus = REFRESH_STATUS_NORMAL;
} else if (distanceY < mRefreshViewHeight) {
mCurrentRefreshStatus = REFRESH_STATUS_PULL_DOWN_REFRESH;
} else {
mCurrentRefreshStatus = REFRESH_STATUS_LOOSEN_REFRESHING;
}
if (mRefreshCreator != null) {
mRefreshCreator.onPull(distanceY, mRefreshViewHeight, mCurrentRefreshStatus);
}
}
四、重寫onLayout方法
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
//if (changed) {
if (mRefreshView != null && mRefreshViewHeight <= 0) {
// 獲取頭部刷新View的高度
mRefreshViewHeight = mRefreshView.getMeasuredHeight();
if (mRefreshViewHeight > 0) {
// 隱藏頭部刷新的View marginTop 多留出1px防止無法判斷是不是滾動到頭部問題
setRefreshViewMarginTop(-mRefreshViewHeight + 1);
}
}
// }
}
五古徒、處理刷新回調
/**
* @return Whether it is possible for the child view of this layout to
* scroll up. Override this if the child view is a custom view.
* 判斷是不是滾動到了最頂部拓提,這個是從SwipeRefreshLayout里面copy過來的源代碼
*/
private boolean canScrollUp() {
if (android.os.Build.VERSION.SDK_INT < 14) {
return ViewCompat.canScrollVertically(this, -1) || this.getScrollY() > 0;
} else {
return ViewCompat.canScrollVertically(this, -1);
}
}
/**
* 停止刷新
*/
public void onStopRefresh() {
mCurrentRefreshStatus = REFRESH_STATUS_NORMAL;
restoreRefreshView();
if (mRefreshCreator != null) {
mRefreshCreator.onStopRefresh();
}
}
// 處理刷新回調監(jiān)聽
private OnRefreshListener mListener;
public void setOnRefreshListener(OnRefreshListener listener) {
this.mListener = listener;
}
public interface OnRefreshListener {
void onRefresh();
}
六、具體使用
實現(xiàn)輔助類
public class DefaultRefreshCreator extends RefreshViewCreator {
// 加載數(shù)據(jù)的ImageView
private View mRefreshIv;
@Override
public View getRefreshView(Context context, ViewGroup parent) {
View refreshView = LayoutInflater.from(context).inflate(R.layout.layout_refresh_header_view, parent, false);
mRefreshIv = refreshView.findViewById(R.id.refresh_iv);
return refreshView;
}
@Override
public void onPull(int currentDragHeight, int refreshViewHeight, int currentRefreshStatus) {
float rotate = ((float) currentDragHeight) / refreshViewHeight;
// 不斷下拉的過程中旋轉圖片
mRefreshIv.setRotation(rotate * 360);
}
@Override
public void onRefreshing() {
// 刷新的時候不斷旋轉
RotateAnimation animation = new RotateAnimation(0, 720,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setRepeatCount(-1);
animation.setDuration(1000);
mRefreshIv.startAnimation(animation);
}
@Override
public void onStopRefresh() {
// 停止加載的時候清除動畫
mRefreshIv.setRotation(0);
mRefreshIv.clearAnimation();
}
}
設置
mRecyclerView.addRefreshViewCreator(new DefaultRefreshCreator());