RecyclerView的上拉加载更多 体验优化
大家好,第一次发帖,还请多包容哈。
使用RecyclerView已经一段时间了,之前使用的一种上拉加载更多忘了是哪个大神写的了,总的来说都还不错,但是在加载更多时会把RecyclerView顶起来,完成后会在原封不动的拉下来,在这一套动作中用户不能感知到是否加载成功,体验不是很好。
个人比较喜欢ListView时代的体验,所以结合先驱的思路改进了一套新的,与大家探讨。
先上效果
为了保证扩展性,代码层并未深入封装,大家可以根据自己的项目封装、优化等。
项目主体为3个部分
1>CustomLinearLayoutManager 功能:控制RecyclerView滑动
public class CustomLinearLayoutManager extends LinearLayoutManager { public CustomLinearLayoutManager(Context context) { super(context); } public CustomLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public CustomLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } private boolean isScrollEnabled = true; public void setScrollEnabled(boolean flag) { this.isScrollEnabled = flag; } @Override public boolean canScrollVertically() { return isScrollEnabled && super.canScrollVertically(); } }
2>FooterCallBack 功能:加载更多事件回调
public interface FooterCallBack { void onPull();//上拉加载更多 void onUp();//释放加载更多 void onLoading(FRecyclerView view);//加载更多中... }
3>FRecyclerView 功能:逻辑处理类
public class FRecyclerView extends RelativeLayout{ @IdRes private final static int RecycleId = 0x3300001; private RecyclerView mRecycler; private boolean isButtom = false; private float downX, downY; private View mFooterView; private FooterCallBack mBack; private int footerHeight = dipToPx(60); private int dipToPx(int dip) { return (int) (dip * getContext().getResources().getDisplayMetrics().density + 0.5f); } public FRecyclerView(Context context) { super(context); onCreate(); } public FRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); onCreate(); } public FRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); onCreate(); } public void onCreate() { mRecycler = new RecyclerView(getContext()); mRecycler.setId(RecycleId); addView(mRecycler, new LayoutParams(-1, -1)); mRecycler.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { CustomLinearLayoutManager manager = (CustomLinearLayoutManager) mRecycler.getLayoutManager(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if(manager == null) break; int lastVisibleItem = manager.findLastCompletelyVisibleItemPosition(); int totalItemCount = manager.getItemCount(); // 判断是否滚动到底部 if (lastVisibleItem == (totalItemCount - 1)) { isButtom = true; downX = event.getX(); downY = event.getY(); manager.setScrollEnabled(false); return true; } break; case MotionEvent.ACTION_MOVE: if(isButtom) { if(event.getY() < downY && Math.abs(event.getY() - downY) > Math.abs(event.getX() - downX)) { int moveRange = (int) (downY - event.getY()); if(moveRange > footerHeight *2) moveRange = footerHeight * 2; //设置recycleView位置 mRecycler.setPadding(mRecycler.getPaddingLeft(), mRecycler.getPaddingTop(), mRecycler.getPaddingRight(), moveRange); //保证内容在最后一行 mRecycler.scrollToPosition(manager.getItemCount() -1); //设置FooterView位置 LayoutParams footerParams = (LayoutParams) mFooterView.getLayoutParams(); footerParams.topMargin = 0 - mRecycler.getPaddingBottom(); mFooterView.setLayoutParams(footerParams); //回调 if(mRecycler.getPaddingBottom() < footerHeight) { mBack.onPull(); } else { mBack.onUp(); } } } break; case MotionEvent.ACTION_UP: if(isButtom) { isButtom = false; if(mRecycler.getPaddingBottom() >= footerHeight) { mRecycler.setPadding(mRecycler.getPaddingLeft(), mRecycler.getPaddingTop(), mRecycler.getPaddingRight(), footerHeight); LayoutParams footerParams = (LayoutParams) mFooterView.getLayoutParams(); footerParams.topMargin = 0-footerHeight; mFooterView.setLayoutParams(footerParams); new android.os.Handler().postDelayed(new Runnable() { @Override public void run() { mBack.onLoading(FRecyclerView.this); } }, 300); } else { mRecycler.setPadding(mRecycler.getPaddingLeft(), mRecycler.getPaddingTop(), mRecycler.getPaddingRight(), 0); LayoutParams footerParams = (LayoutParams) mFooterView.getLayoutParams(); footerParams.topMargin = 0; mFooterView.setLayoutParams(footerParams); if(manager == null) break; manager.setScrollEnabled(true); } } break; } return false; } }); } //获取RecyclerView public RecyclerView getRecycleView() { return mRecycler; } //添加Footer public void setFooter(View view, FooterCallBack back) { if(view == null || back == null) { new NullPointerException("FooterView or FooterCallBack can not null"); } mFooterView = view; addView(mFooterView, new LayoutParams(-1, footerHeight)); mBack = back; LayoutParams params = (LayoutParams) mFooterView.getLayoutParams(); params.addRule(BELOW, RecycleId); } //数据加载完成后调用 -- 状态回复 public void onCompleted() { CustomLinearLayoutManager manager = (CustomLinearLayoutManager) mRecycler.getLayoutManager(); mRecycler.setPadding(mRecycler.getPaddingLeft(), mRecycler.getPaddingTop(), mRecycler.getPaddingRight(), 0); LayoutParams footerParams = (LayoutParams) mFooterView.getLayoutParams(); footerParams.topMargin = 0; mFooterView.setLayoutParams(footerParams); if(manager == null) return; manager.setScrollEnabled(true); Log.e("aa", ((LayoutParams) mFooterView.getLayoutParams()).topMargin + "------" + mRecycler.getPaddingBottom() + "---------" + mRecycler.getLayoutParams().height); } }
最后附上项目的下载地址:
http://pan.baidu.com/s/1jIdy1Vo