首页 >> 大全

如何利用RecyclerView打造炫酷滑动卡片

2023-09-30 大全 18 作者:考证青年

效果

没错,就是上面这玩意儿,是不是很炫酷,本着发扬一名码农的职业精神,我心里便痒痒的想实现这种效果,当然因为长期的fork ,第一时间我还是上网搜了搜,有木有哪位好心人已经开源了类似的控件。借助强大的,我马上搜到了一个项目 ,是仿照探探的老父亲的app动画效果打造的,果然程序员都一个操行,看到好看的就想动手实现,不过人家的成绩让我可望而不可及~

他实现的效果是这样的:

嗯,还不错,为了进行思想上的碰撞,我就了一下他的源码,稍稍read了一下~_~

作为一个有思想,有抱负的程序员,怎么能满足于别人的库呢?必须得自己动手,丰衣足食啊!

正式开工 思考

一般这种View都是自定义的,然后重写,但是有木有更简单的方法呢?由于项目里一直使用,那么能不能用来实现这种效果呢?能,当然能啊!得力于优雅的扩展性,我们完全可以自定义一个来实现嘛。

布局实现

可以通过自定义来实现各种布局,官方自己提供了、,相比于,可谓是方便了不少。同样,我们也可以通过自定义,实现这种View一层层叠加的效果。

自定义,最重要的是要重写()

@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {detachAndScrapAttachedViews(recycler);for (int i = 0; i < getItemCount(); i++) {View child = recycler.getViewForPosition(i);measureChildWithMargins(child, 0, 0);addView(child);int width = getDecoratedMeasuredWidth(child);int height = getDecoratedMeasuredHeight(child);layoutDecorated(child, 0, 0, width, height);if (i < getItemCount() - 1) {child.setScaleX(0.8f);child.setScaleY(0.8f);}}
}

这种布局实现起来其实相当简单,因为每个child的left和top都一样,直接设置为0就可以了,这样child就依次叠加在一起了,至于最后两句,主要是为了使顶部Child之下的有一种缩放的效果。

动画实现

下面到了最重 要的地方 了,主要分为以下几个部分。

(1)手势追踪

当手指按 下时,我们 需要取到 iew的顶部Child,并让其跟随手指滑动

public boolean onTouchEvent(MotionEvent e) {if (getChildCount() == 0) {return super.onTouchEvent(e);}View topView = getChildAt(getChildCount() - 1);float touchX = e.getX();float touchY = e.getY();switch (e.getAction()) {case MotionEvent.ACTION_DOWN:mTopViewX = topView.getX();mTopViewY = topView.getY();mTouchDownX = touchX;mTouchDownY = touchY;break;case MotionEvent.ACTION_MOVE:float dx = touchX - mTouchDownX;float dy = touchY - mTouchDownY;topView.setX(mTopViewX + dx);topView.setY(mTopViewY + dy);updateNextItem(Math.abs(topView.getX() - mTopViewX) * 0.2 / mBorder + 0.8);break;case MotionEvent.ACTION_UP:mTouchDownX = 0;mTouchDownY = 0;touchUp(topView);break;}return super.onTouchEvent(e);
}

手指按下的时候,记录t w的位置,移动的时候,根据偏移量,动态调整的位置,就实 现了基本效果。但是这样还不够,记得我们在实现布局时,对其他子View进行了缩放吗?那时候的缩放是为 现在做准备的。当手指在屏幕上滑动时,我们同样会 调用(),对top 下面的子view进行缩放。

private void updateNextItem(double factor) {if (getChildCount() < 2) {return;}if (factor > 1) {factor = 1;}View nextView = getChildAt(getChildCount() - 2);nextView.setScaleX((float) factor);nextView.setScaleY((float) factor);
}

这里的计算很简单,只要当 dView滑动到设置 的边界时,nextV iew刚好缩放到原本大小,即=1,就可以了。因为一开始缩放为0.8,所以可计算出:

factor=Math.abs(topView.getX() - mTopViewX) * 0.2 / mBorder + 0.8

(2)抬起手指

手指抬起后,我们要进行状态判断

1.滑动未超过边界

此时我们需要对进行归位。

2.超过边界

此时我们需要根据滑动方向,使飞离屏幕。

对于这两种情况,我们都是通过计算view的终 点坐标,然后利用动画实现的。对于第一种,很简单,和直接就是的原始坐标。但是对于第二种,需要根据的原始坐标和目前坐标,计算出线性表达式,然后再根据来计算,至于,往右飞就可以赋为,而往左就直接为0-view.width,只要终点在屏幕外就可以。具 体代 码如 下。

private void touchUp(final View view) {float targetX = 0;float targetY = 0;boolean del = false;if (Math.abs(view.getX() - mTopViewX) < mBorder) {targetX = mTopViewX;targetY = mTopViewY;} else if (view.getX() - mTopViewX > mBorder) {del = true;targetX = getScreenWidth()*2;mRemovedListener.onRightRemoved();} else {del = true;targetX = -view.getWidth()-getScreenWidth();mRemovedListener.onLeftRemoved();}View animView = view;TimeInterpolator interpolator = null;if (del) {animView = getMirrorView(view);float offsetX = getX() - mDecorView.getX();float offsetY = getY() - mDecorView.getY();targetY = caculateExitY(mTopViewX + offsetX, mTopViewY + offsetY, animView.getX(), animView.getY(), targetX);interpolator = new LinearInterpolator();} else {interpolator = new OvershootInterpolator();}final boolean finalDel = del;animView.animate().setDuration(500).x(targetX).y(targetY).setInterpolator(interpolator).setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {if (!finalDel) {updateNextItem(Math.abs(view.getX() - mTopViewX) * 0.2 / mBorder + 0.8);}}});}

对于第二种情况,如果直接启动动 画,并在动画结束时通知删除item,在连续操作时,会导致数据错乱。但是如果在动画启动时直接移除item,又会失去动画效果。所以我在这里采用了另一种办法,在动画开始前 创建一个与 一模一样的镜像View,添加到上,并隐藏删除掉,然后利用镜像View来展示动画。添加镜像View的代码如下:

private ImageView getMirrorView(View view) {view.destroyDrawingCache();view.setDrawingCacheEnabled(true);final ImageView mirrorView = new ImageView(getContext());Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());mirrorView.setImageBitmap(bitmap);view.setDrawingCacheEnabled(false);FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(bitmap.getWidth(), bitmap.getHeight());int[] locations = new int[2];view.getLocationOnScreen(locations);mirrorView.setAlpha(view.getAlpha());view.setVisibility(GONE);((SwipeCardAdapter) getAdapter()).delTopItem();mirrorView.setX(locations[0] - mDecorViewLocation[0]);mirrorView.setY(locations[1] - mDecorViewLocation[1]);mDecorView.addView(mirrorView, params);return mirrorView;
}

因为镜像View是添加 在 上的,父容器是Re ,而View的x、y是相对于父容器而言的,所以镜像View的和需要加上一定偏移量。

好了到这里,一切就准 备就绪了,下面让我们看看动画效 果如何。

总结

效果 是 不是 还 不错,项目 地址在 这里: ,欢迎大家fork AND star!也希望大家在使用app,看到一些酷炫效果的时候,也自己 去动手实现,谁让 我们是有 着职业精 神的 码农 呢!

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了