本文主要是介绍仿饿了么下拉刷新,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
使用RecyclerView仿饿了么下拉刷新
经常用饿了么点餐,看到这个下拉刷新,模仿一波。
效果图
Step1
自定义EleView.这个view就是根据RecyclerView的onTouch移动的距离,显示处理篮子打开和冒出水果的动画。这里有两个偏移,坐标(篮子位移)与角度(篮子盖打开)偏移,所以需要一个onMove方法统一传入偏移的百分百percent,再计算和重绘。
public void onMove(float percent) {if (percent >= 0.6) {currentDegree = (float) (150 * (percent - 0.6) * 2.5);}if (percent <= 1) {offsetY = percent * maxOffsetY;invalidate();}}
在onDraw方法里面可以先绘制静态的图,在根据偏移统一调整坐标和角度。这里篮子有个迷の带感的震动效果,实现也是用属性动画:
cycleAnimator = ValueAnimator.ofFloat(-1, 1);cycleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {currentOffset = (float) animation.getAnimatedValue();invalidate();}});......
通过currentOffset变化,影响绘制的canvas.drawBitmap传入的Rect dst的坐标,造成影像的缩放。
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.translate(mWidth / 2, offsetY);for (int i = 0; i < 5; i++) {dstFruit.left = (int) (mPosition0[i][0] - 0.5 * fW);dstFruit.top = (int) (mPosition0[i][1] - 0.5 * fH);dstFruit.right = (int) (mPosition0[i][0] + 0.5 * fW);dstFruit.bottom = (int) (mPosition0[i][1] + 0.5 * fH);if (foods.get(i).showing) {canvas.drawBitmap(foods.get(i).bitmap, null, dstFruit, paint);}}canvas.save();int offsetC = (int) (currentOffset * 5);canvas.rotate(currentDegree, (float) (dstE.right - iWidth * scale / 4), (float) (dstE.top + scale * iWidth));canvas.drawBitmap(iR, null, new Rect(dstI2.left, dstI2.top - offsetC, dstI2.right, dstI2.bottom + offsetC), paint);canvas.restore();canvas.save();canvas.rotate(-currentDegree, (float) (dstE.left + iWidth * scale / 4), (float) (dstE.top + scale * iWidth));canvas.drawBitmap(iL, null, new Rect(dstI.left, dstI.top - offsetC, dstI.right, dstI.bottom + offsetC), paint);canvas.restore();canvas.drawBitmap(ele, null, new Rect(dstE.left, dstE.top - offsetC, dstE.right, dstE.bottom + offsetC), paint);}
水果移动需要得到水果移动的路径,在根据路径算出坐标。路径很好得到,大概估计一下就行。获取到路径在获取每个点的坐标,这里用到了PathMeasure的getPosTan(float distance, float pos[], float tan[]),简单的说就是把这个路径拉直成一条直线,然后根据当前位移获取当前的坐标,封装到数组中去。由于现在有5个水果需要移动,新建二位数组mPosition0 = new float[5][2];
for (int i = 0; i < 5; i++) {final int finalI = i;ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.get(finalI).getLength());valueAnimator.setDuration(duration);valueAnimator.setInterpolator(new DecelerateInterpolator());valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float value = (Float) animation.getAnimatedValue();// 获取当前点坐标封装到mCurrentPositionmPathMeasure.get(finalI).getPosTan(value, mPosition0[finalI], null);postInvalidate();}});}
Step2
新建一个MyHeaderView 继承LinearLayout。这里为了方便以后的拓展,抽取一个接口:之后只要实现了这个接口,就可以传入到ERecyclerView充当刷新的HeadView。
public interface Header {int STATE_NORMAL = 0;int STATE_READY = 1;int STATE_REFRESHING = 2;int STATE_DONE = 3;void setVisibleHeight(int height);int getVisibleHeight();void setState(int state);void onMove(float delta);void refreshComplete();boolean releaseAction();
}
Step3
自定义RecyclerView主要是处理当onTouchEvent。其实还有其他的地方但不是本文的重点。
.....private Header headerView;@Overridepublic boolean onTouchEvent(MotionEvent e) {if (mLastY == -1) {mLastY = e.getRawY();}if (isOnTop() && !isloading) {switch (e.getAction()) {case MotionEvent.ACTION_DOWN:mLastY = e.getRawY();break;case MotionEvent.ACTION_MOVE:float delta = e.getRawY() - mLastY;mLastY = e.getRawY();headerView.onMove(delta / 1.5f);break;default:if (headerView.releaseAction() && freshListener != null && !isloading) {noMore = false;isloading = true;freshListener.onRefresh();}mLastY = -1;break;}}return super.onTouchEvent(e);}
差不多就这些,没错就是这么短小精悍!还有其他的具体代码细节请看项目源码,如果觉得不错顺手点个star也是极好的O(∩_∩)O哈哈~:
https://github.com/Ulez/ERecyclerView
这篇关于仿饿了么下拉刷新的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!