Android之View篇6————仿陌陌卡片左右滑动选择布局

太过爱你忘了你带给我的痛 2022-05-18 08:53 492阅读 0赞

Android之View篇6————仿陌陌卡片左右滑动选择控件

一.目录

  • Android之View篇6————仿陌陌卡片左右滑动选择控件

      • 一.目录
      • 二.效果图
      • 三.业务需求梳理
      • 四.思路分析

          1. 新建TinderCardView类,并继承FrameLayout
          1. 新建TinderStackLayout 类,并继承FrameLayout
      • 五.源码地址

二.效果图

这里写图片描述

三.业务需求梳理

  1. 卡片随着手指的移动进行移动
  2. 卡片在移动过程中,随着距离的加大,卡片绕z轴旋转
  3. 判断手指的移动方向,显示选择/删除图标,同时图标随距离的增大,透明度增加
  4. 手指离开卡片后,根据移动的距离,判断卡片是否移出屏幕,从左边移动还是右边移动
  5. 显示的卡片移出完后,增加新的卡片。
  6. 显示的4张卡片,需要展示出卡片的层次感

四.思路分析

根据上面的业务逻辑梳理,明显可以知道,实现该功能需要自定义两个View,一个是卡片View(TinderCardView),一个是卡片的容器(TinderStackLayout)。

需求1,2,3都是手指移动过程中发生,即MotionEvent的ACTION_MOVE事件中。

MotionEvent 这一块不知道的可以看我前面写的博客Android之View篇2————View的事件分发

需求4是在手指离开屏幕后中发生的,即MotionEvent的MotionEvent.ACTION_UP事件中

需求5是卡片动画结束后,判断剩余卡片数量,选择是否要加载新的卡片

需求6是加载新卡片时,要求实现的。

1. 新建TinderCardView类,并继承FrameLayout

a.TinderCardView即展示信息的卡片类,重写其onTouch方法

  1. @Override
  2. public boolean onTouch(final View view, MotionEvent motionEvent) {
  3. TinderStackLayout tinderStackLayout = ((TinderStackLayout) view.getParent());
  4. TinderCardView topCard = (TinderCardView) tinderStackLayout.getChildAt(tinderStackLayout.getChildCount() - 1);
  5. if (topCard.equals(view)) {
  6. switch (motionEvent.getAction()) {
  7. case MotionEvent.ACTION_DOWN:
  8. downX = motionEvent.getX();
  9. downY = motionEvent.getY();
  10. view.clearAnimation();
  11. return true;
  12. case MotionEvent.ACTION_MOVE:
  13. newX = motionEvent.getX();
  14. newY = motionEvent.getY();
  15. dX = newX - downX; //手指移动距离
  16. dY = newY - downY;
  17. float posX = view.getX() + dX;
  18. view.setX(view.getX() + dX); //view的新距离 需求1,卡片随手指的移动而移动
  19. view.setY(view.getY() + dY);
  20. float rotation = (CARD_ROTATION_DEGREES * (posX)) / screenWidth;
  21. int halfCardHeight = (view.getHeight() / 2);
  22. if (downY < halfCardHeight - (2 * padding)) {
  23. view.setRotation(rotation); //设置View在Z轴上的旋转角度 需求2,卡片移动过程中,随距离的增大而,选择角度增大
  24. } else {
  25. view.setRotation(-rotation);
  26. }
  27. float alpha = (posX - padding) / (screenWidth * 0.3f);
  28. if (alpha > 0) { //需求3, 判断手指的移动方向,显示选择/删除图标,同时图标随距离的增大,透明度增加
  29. iv_tips.setAlpha(alpha);
  30. iv_tips.setImageResource(R.drawable.ic_like);
  31. } else {
  32. iv_tips.setAlpha(-alpha);
  33. iv_tips.setImageResource(R.drawable.ic_nope);
  34. }
  35. return true;
  36. case MotionEvent.ACTION_UP: //需求4. 手指离开卡片后,根据移动的距离,判断卡片是否移出屏幕,从左边移动还是右边移动
  37. if (isBeyondLeftBoundary(view)) {
  38. removeCard(view, -(screenWidth * 2)); //移动view.向左边移出屏幕
  39. } else if (isBeyondRightBoundary(view)) {
  40. removeCard(view, (screenWidth * 2));
  41. } else {
  42. resetCard(view); //复原view
  43. }
  44. return true;
  45. default:
  46. return super.onTouchEvent(motionEvent);
  47. }
  48. }
  49. return super.onTouchEvent(motionEvent);
  50. }

b.判断是否左右移动距离是否达到要求

  1. private boolean isBeyondLeftBoundary(View view) {
  2. return (view.getX() + (view.getWidth() / 2) < leftBoundary);
  3. }
  4. private boolean isBeyondRightBoundary(View view) {
  5. return (view.getX() + (view.getWidth() / 2) > rightBoundary);
  6. }

c.卡片移出屏幕和复原动画

  1. private void removeCard(final View view, int xPos) { //移出屏幕动画
  2. view.animate()
  3. .x(xPos) //x轴移动距离
  4. .y(0) //y轴移动距离
  5. .setInterpolator(new AccelerateInterpolator()) //插值器 在动画开始的地方速率改变比较慢,然后开始加速
  6. .setDuration(DURATIONTIME) //移动距离
  7. .setListener(new Animator.AnimatorListener() { //监听
  8. @Override
  9. public void onAnimationStart(Animator animator) {
  10. }
  11. @Override
  12. public void onAnimationEnd(Animator animator) {
  13. //移出后回调
  14. ViewGroup viewGroup = (ViewGroup) view.getParent();
  15. if (viewGroup != null) {
  16. viewGroup.removeView(view);
  17. int count = viewGroup.getChildCount();
  18. if (count == 1 && listener != null) { //需求5,增加新卡片
  19. listener.onLoad();
  20. }
  21. }
  22. }
  23. @Override
  24. public void onAnimationCancel(Animator animator) {
  25. }
  26. @Override
  27. public void onAnimationRepeat(Animator animator) {
  28. }
  29. });
  30. }
  31. private void resetCard(final View view) { //还原动画
  32. view.animate()
  33. .x(0) //x轴移动
  34. .y(0) //y轴移动
  35. .rotation(0) //循环次数
  36. .setInterpolator(new OvershootInterpolator()) //插值器 向前甩一定值后再回到原来位置
  37. .setDuration(DURATIONTIME);
  38. iv_tips.setAlpha(0f); //图标隐藏
  39. }

2. 新建TinderStackLayout 类,并继承FrameLayout

a.数据的初始化添加

  1. public void setDatas(List<User> list) { //提供给activity调用
  2. this.mList = list;
  3. if (mList == null) {
  4. return;
  5. }
  6. for (int i = index; index < i + STACK_SIZE; index++) {
  7. tc = new TinderCardView(getContext());
  8. tc.bind(mList.get(index));
  9. tc.setOnLoadMoreListener(this);
  10. addCard(tc);
  11. }
  12. }
  13. private void addCard(TinderCardView view) {
  14. int count = getChildCount();
  15. addView(view, 0, params);
  16. float scaleX = 1 - (count / BASESCALE_X_VALUE);
  17. view.animate()
  18. .x(0)
  19. .y(count * scaleY) //需求6,实现层次感
  20. .scaleX(scaleX) //水平缩放比例
  21. .setInterpolator(new AnticipateOvershootInterpolator())
  22. .setDuration(DURATIONTIME);
  23. }

b.实现接口onLoad() 供TinderCardView类调用

  1. @Override
  2. public void onLoad() { //当显示卡片数量==1时,TinderCardView调用该方法添加新卡片
  3. for (int i = index; index < i + (STACK_SIZE - 1); index++) {
  4. if (index == mList.size()) {
  5. return;
  6. }
  7. tc = new TinderCardView(getContext());
  8. tc.bind(mList.get(index));
  9. tc.setOnLoadMoreListener(this);
  10. addCard(tc);
  11. }
  12. int childCount = getChildCount();
  13. for (int i = childCount - 1; i >= 0; i--) {
  14. TinderCardView tinderCardView = (TinderCardView) getChildAt(i);
  15. if (tinderCardView != null) {
  16. float scaleValue = 1 - ((childCount - 1 - i) / 50.0f);
  17. tinderCardView.animate()
  18. .x(0)
  19. .y((childCount - 1 - i) * scaleY)
  20. .scaleX(scaleValue)
  21. .rotation(0)
  22. .setInterpolator(new AnticipateOvershootInterpolator())
  23. .setDuration(DURATIONTIME);
  24. }
  25. }
  26. }

五.源码地址

点位查看源码

发表评论

表情:
评论列表 (有 0 条评论,492人围观)

还没有评论,来说两句吧...

相关阅读

    相关 直播全景监控系统实践

    系统建设背景 随着移动互联网技术的高速发展,人们喜欢的媒体交互方式也由文字、图片、小视频迅速切换到了直播。作为一种新兴的社交方式,直播在实时性、交互性方面具备先天优势,这