简介:
突发奇想好多APP的列表视图都有下拉刷新的功能,可能大家会联想到ListView或RecyclerView,今天就针对RecyclerView说说下拉刷新是怎样实现的?
如果有不了解RecyclerView的原理请看
快速了解传送门:https://www.jianshu.com/p/4f9591291365
本文代码附在文章的末尾
基本实现原理:
首先了解一下当触发下拉手势的几种状态
1:当手指触摸屏幕后并向下滑动,此下拉过程中有两种状态第一个为下拉状态,第二个为到了一个零界点该改变状态为释放刷新的状态
2:当手指离开屏幕后会有三种状态,第一种刷新中,第二种刷新成功或者失败
3:刷新成功或者失败时候刷新状态回归为默认未刷新的状态
public static final int HEAD_STATE_NORMAL = 0;//正常
public static final int HEAD_STATE_RELEASE_TO_REFRESH = 1;//释放
public static final int HEAD_STATE_REFRESHING = 2;//刷新
public static final int HEAD_STATE_SUCCESS = 3;//刷新成功
public static final int HEAD_STATE_FAIL = 4;//刷新失败
public static final int HEAD_STATE_RETREAT_NORMAL = 5;//后退到正常
滑动函数:
final void onMove(float move) {
//动画没有执行则为true
if (!isAnimation) {
//System.out.println("刷新高度: " + getVisibleHeight());
if (mHeadRefreshState == HEAD_STATE_NORMAL
|| mHeadRefreshState == HEAD_STATE_RETREAT_NORMAL
|| mHeadRefreshState == HEAD_STATE_RELEASE_TO_REFRESH) {
int newVisibleHeight = (int) (getVisibleHeight() + Math.floor(move / 2.5));
setVisibleHeight(newVisibleHeight);
//如果当前高度等于0
if (getVisibleHeight() == 0) {
mHeadRefreshState = HEAD_STATE_NORMAL;
}
//如果当前高度小于刷新高度
else if (getVisibleHeight() < refreshHeight) {
mHeadRefreshState = HEAD_STATE_RETREAT_NORMAL;
onPullingDown();
}
//如果当前高度大于刷新高度
else if (getVisibleHeight() > refreshHeight) {
mHeadRefreshState = HEAD_STATE_RELEASE_TO_REFRESH;
onReleaseState();
}
}
}
}
手指离开
//手指离开
final void onUp() {
//动画没有执行则为true
if (!isAnimation) {
//状态正常和动画不在运行的时则为true
if (mHeadRefreshState == HEAD_STATE_RETREAT_NORMAL) {
smoothScrollTo(0);
} else if (mHeadRefreshState == HEAD_STATE_RELEASE_TO_REFRESH) {
mHeadRefreshState = HEAD_STATE_REFRESHING;
onRefreshing();
smoothScrollTo(refreshHeight);//回退到刷新的临界点高度
}
}
}
刷新类是继承LinearLayout的并且设置成一个抽象的类,方便扩展,然后包装在RecyclerView Adapter中
public abstract class AbsRefreshHeaderView extends LinearLayout
刷新动画
private void smoothScrollTo(int height) {
ValueAnimator animator = ValueAnimator.ofInt(getVisibleHeight(), height);
animator.setDuration(260);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setVisibleHeight((int) animation.getAnimatedValue());
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
isAnimation = animation.isRunning();//true
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isAnimation = animation.isRunning();//false
if (mHeadRefreshState == HEAD_STATE_REFRESHING) {
refreshListener.refresh();
}
//如果状态成功或者失败后恢复状态为默认的状态
if (mHeadRefreshState == HEAD_STATE_SUCCESS || mHeadRefreshState == HEAD_STATE_FAIL) {
mHeadRefreshState = HEAD_STATE_NORMAL;
}
}
});
animator.start();
}
以下是实现该功能的全部代码
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.LinearLayout;
public abstract class AbsRefreshHeaderView extends LinearLayout {
//刷新监听
private RefreshListener refreshListener;
public static final int HEAD_STATE_NORMAL = 0;//正常
public static final int HEAD_STATE_RELEASE_TO_REFRESH = 1;//释放
public static final int HEAD_STATE_REFRESHING = 2;//刷新
public static final int HEAD_STATE_SUCCESS = 3;//刷新成功
public static final int HEAD_STATE_FAIL = 4;//刷新失败
public static final int HEAD_STATE_RETREAT_NORMAL = 5;//后退到正常
private int mHeadRefreshState;//刷新状态
private int refreshHeight;//触发刷新的高度
private boolean isAnimation = false;//动画是否完成
public AbsRefreshHeaderView(Context context) {
this(context, null);
}
public AbsRefreshHeaderView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public AbsRefreshHeaderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setRefreshHeight();
init();
}
//初始化
protected abstract void init();
//正在下拉
protected abstract void onPullingDown();
//已经达到可以刷新的状态
protected abstract void onReleaseState();
//执行刷新
protected abstract void onRefreshing();
//刷新成功
protected abstract void onResultSuccess();
//刷新失败
protected abstract void onResultFail();
protected void setRefreshHeight() {
refreshHeight = (int) (Resources.getSystem().getDisplayMetrics().density * 90 + 0.5F);
}
//获取head高度
protected int getVisibleHeight() {
return getLayoutParams().height;
}
protected boolean getIsNormal() {
return getVisibleHeight() == 0 && mHeadRefreshState == HEAD_STATE_NORMAL;
}
//是否在刷新中(刷新中包含刷新成功或失败)
protected boolean getIsRefreshing() {
return mHeadRefreshState == HEAD_STATE_REFRESHING
|| mHeadRefreshState == HEAD_STATE_FAIL
|| mHeadRefreshState == HEAD_STATE_SUCCESS;
}
//设置head高度
public void setVisibleHeight(int height) {
height = height < 0 ? 0 : height;
ViewGroup.LayoutParams lp = getLayoutParams();
lp.height = height;
setLayoutParams(lp);
}
private void smoothScrollTo(int height) {
ValueAnimator animator = ValueAnimator.ofInt(getVisibleHeight(), height);
animator.setDuration(260);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setVisibleHeight((int) animation.getAnimatedValue());
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
isAnimation = animation.isRunning();//true
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isAnimation = animation.isRunning();//false
if (mHeadRefreshState == HEAD_STATE_REFRESHING) {
refreshListener.refresh();
}
//如果状态成功或者失败后恢复状态为默认的状态
if (mHeadRefreshState == HEAD_STATE_SUCCESS || mHeadRefreshState == HEAD_STATE_FAIL) {
mHeadRefreshState = HEAD_STATE_NORMAL;
}
}
});
animator.start();
}
//手指移动 该方法只涉及到头部高度,没有涉及到动画
final void onMove(float move) {
//动画没有执行则为true
if (!isAnimation) {
//System.out.println("刷新高度: " + getVisibleHeight());
if (mHeadRefreshState == HEAD_STATE_NORMAL
|| mHeadRefreshState == HEAD_STATE_RETREAT_NORMAL
|| mHeadRefreshState == HEAD_STATE_RELEASE_TO_REFRESH) {
int newVisibleHeight = (int) (getVisibleHeight() + Math.floor(move / 2.5));
setVisibleHeight(newVisibleHeight);
//如果当前高度等于0
if (getVisibleHeight() == 0) {
mHeadRefreshState = HEAD_STATE_NORMAL;
}
//如果当前高度小于刷新高度
else if (getVisibleHeight() < refreshHeight) {
mHeadRefreshState = HEAD_STATE_RETREAT_NORMAL;
onPullingDown();
}
//如果当前高度大于刷新高度
else if (getVisibleHeight() > refreshHeight) {
mHeadRefreshState = HEAD_STATE_RELEASE_TO_REFRESH;
onReleaseState();
}
}
}
}
//手指离开
final void onUp() {
//动画没有执行则为true
if (!isAnimation) {
//状态正常和动画不在运行的时则为true
if (mHeadRefreshState == HEAD_STATE_RETREAT_NORMAL) {
smoothScrollTo(0);
} else if (mHeadRefreshState == HEAD_STATE_RELEASE_TO_REFRESH) {
mHeadRefreshState = HEAD_STATE_REFRESHING;
onRefreshing();
smoothScrollTo(refreshHeight);//回退到刷新的临界点高度
}
}
}
//判断刷新是否成功
final void setRefreshState(boolean isSuccess) {
if (!isAnimation) {
if (isSuccess) {
mHeadRefreshState = HEAD_STATE_SUCCESS;
onResultSuccess();//刷新成功
smoothScrollTo(0);
} else {
mHeadRefreshState = HEAD_STATE_FAIL;
onResultFail();//刷新失败
smoothScrollTo(0);
}
}
}
//刷新成功
public void onRefreshSuccess() {
setRefreshState(true);
}
//刷新失败
public void onRefreshFail() {
setRefreshState(false);
}
//定义刷新的监听
public interface RefreshListener {
void refresh();
}
final void setRefreshListener(RefreshListener listener) {
refreshListener = listener;
}
}
定义一个刷新类的具体实现类
public class SimpleRefreshHeaderView extends AbsRefreshHeaderView {
private TextView mTvTip;
public SimpleRefreshHeaderView(Context context) {
super(context);
}
public SimpleRefreshHeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SimpleRefreshHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void init() {
LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
setLayoutParams(params);
setGravity(Gravity.BOTTOM);
View view = LayoutInflater.from(getContext()).inflate(R.layout.header_refresh_view, this, false);
mTvTip = view.findViewById(R.id.tv_tip);
addView(view);
}
@Override
protected void onPullingDown() {
mTvTip.setText(R.string.pull_to_refresh);
}
@Override
protected void onReleaseState() {
mTvTip.setText(R.string.release_refresh);
}
@Override
protected void onRefreshing() {
mTvTip.setText(R.string.refreshing);
}
@Override
protected void onResultSuccess() {
mTvTip.setText(R.string.refresh_success);
}
@Override
protected void onResultFail() {
mTvTip.setText(R.string.refresh_fail);
}
}
然后把该刷新视图包装到RecyclerView中
public class RecyclerPlusView extends RecyclerView {
private RecyclerPlusAdapter mRecyclerPlusAdapter;
private AbsRefreshHeaderView absRefreshHeaderView;
private PullListener pullListener;
private float lastY;
public RecyclerPlusView(Context context) {
super(context);
}
public RecyclerPlusView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public RecyclerPlusView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setAdapter(Adapter adapter) {
if (adapter != null) {
mRecyclerPlusAdapter = new RecyclerPlusAdapter(adapter);
super.setAdapter(mRecyclerPlusAdapter);
}
}
private class RecyclerPlusAdapter extends Adapter<ViewHolder> {
private static final int TYPE_REFRESH_HEADER = 10000;
private Adapter mAdapter;
public RecyclerPlusAdapter(Adapter adapter) {
mAdapter = adapter;
}
@Override
public int getItemCount() {
int count = 0;
if (absRefreshHeaderView != null) {
count++;
}
if (mAdapter != null) {
count += mAdapter.getItemCount();
}
return count;
}
@Override
public int getItemViewType(int position) {
if (absRefreshHeaderView != null && position == 0) {
return TYPE_REFRESH_HEADER;
}
return 0;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == TYPE_REFRESH_HEADER) {
return new PlusHolder(absRefreshHeaderView);
}
return mAdapter.onCreateViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
}
private class PlusHolder extends ViewHolder {
public PlusHolder(View itemView) {
super(itemView);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent e) {
if (absRefreshHeaderView != null) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = e.getRawY();
break;
case MotionEvent.ACTION_MOVE:
float moveY = e.getRawY() - lastY;
lastY = e.getRawY();
if (isTop()) {
absRefreshHeaderView.onMove(moveY);
//Log.d("headView: ", String.valueOf(refreshHeadView.getVisibleHeight()));
if (absRefreshHeaderView.getIsNormal()) {
//Log.d("isNormal: ", String.valueOf(refreshHeadView.getIsNormal()));
return super.onTouchEvent(e);
}
return false;
}
case MotionEvent.ACTION_UP:
absRefreshHeaderView.onUp();
break;
}
}
return super.onTouchEvent(e);
}
private boolean isTop() {
return absRefreshHeaderView.getParent() != null;
}
//定义下拉上拉监听
public interface PullListener {
void refresh();
}
//设置下拉刷新上拉加载监听
public void setPullListener(PullListener listener) {
this.pullListener = listener;
if (getAdapter() != null) {
initRefresh();
}
}
//初始化刷新
private void initRefresh() {
if (absRefreshHeaderView == null) {
absRefreshHeaderView = new SimpleRefreshHeaderView(getContext());
}
//mPlushAdapter.setRefreshHeaderView(absRefreshHeaderView);
absRefreshHeaderView.setRefreshListener(new AbsRefreshHeaderView.RefreshListener() {
@Override
public void refresh() {
pullListener.refresh();
}
});
}
//判断刷新是否成功
public void onRefreshComplete(boolean success) {
if (success) {
absRefreshHeaderView.onRefreshSuccess();
} else {
absRefreshHeaderView.onRefreshFail();
}
}
}
网友评论