Android之ArcSlidingHelper制作圆弧滑动效果

作者:陈小缘 时间:2021-07-23 03:10:24 

前言

我们平时在开发中,难免会遇到一些比较特殊的需求,就比如我们这篇文章的主题,一个关于圆弧滑动的,一般是比较少见的。其实在遇到这些东西时,不要怕,一步步分析他实现原理,问题便能迎刃而解。

前几天一位群友发了一张图,问类似这种要怎么实现:

  1. 要支持手势旋转

  2. 旋转后惯性滚动

  3. 滚动后自动选中

Android之ArcSlidingHelper制作圆弧滑动效果

哈哈, 来一张自己实现的效果图:

Android之ArcSlidingHelper制作圆弧滑动效果

初步分析

首先我们看下设计图,Item绕着一个半圆旋转,如果我们是自定义ViewGroup的话,那么在onLayout之后,就要把这些Item按一定的角度旋转了。如果直接继承View,这个比较方便,可以直接用Canvas的rotate方法。不过如果继承View的话,做起来是简单,也能满足上面的需求,但局限性就比较大了: 只能draw,而且Item内容不宜过多。所以这次我们打算自定义ViewGroup,它的好处呢就是:什么都能放,我不管你Item里面是什么,反正我就负责显示。惯性滚动的话,这个很容易,我们可以用Scroller配合VelocityTracker来完成。旋转手势,无非就是计算手指滑动的角度。

选择旋转方案

说起View的动画播放,大家肯定都是轻车熟路了,如果一个View,它有监听点击事件,那么在播放位移动画后,监听的位置按道理,也应该在它最新的位置上(即位移后的位置),在这种情况下我们用View的startAnimation就不奏效了:


       TranslateAnimation translateAnimation = new TranslateAnimation(0, 150, 0, 300);
       translateAnimation.setDuration(500);
       translateAnimation.setFillAfter(true);
       mView.startAnimation(translateAnimation);

Android之ArcSlidingHelper制作圆弧滑动效果

可以看到,在View位移之后,监听点击事件的区域还是在原来的地方。我们再看下用属性动画的:


       mView.animate().translationX(150).translationY(300).setDuration(500).start();

Android之ArcSlidingHelper制作圆弧滑动效果

监听点击事件的区域随着View的移动而更新了。嘻嘻,我们通过实践来验证了这个说法。

那么我们做的这个是要支持触摸事件的,肯定是使用第二种方法。 ViewPropertyAnimator的源码分析相信大家之前也都已经看过其他大佬们的文章了,这里就只讲讲关键代码: ViewPropertyAnimator它不是ValueAnimator的子类,哈哈,这个有点意外吧,我们直接看startAnimation方法(这个方法是start()里面调用的):


    private void startAnimation() {
   ...
   //可以看到这里创建了ValueAnimator对象
       ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
       ...
       animator.addUpdateListener(mAnimatorEventListener);
       ...
       animator.start();
   }

中间那里addUpdateListener(mAnimatorEventListener),我们来看看这个listener里面做了什么:


@Override
       public void onAnimationUpdate(ValueAnimator animation) {
       ...
       ...
           ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
           if (valueList != null) {
               int count = valueList.size();
               for (int i = 0; i < count; ++i) {
                   NameValuesHolder values = valueList.get(i);
                   float value = values.mFromValue + fraction * values.mDeltaValue;
                   if (values.mNameConstant == ALPHA) {
                       alphaHandled = mView.setAlphaNoInvalidation(value);
                   } else {
                       setValue(values.mNameConstant, value);
                   }
               }
           }
       ...
       ...
       }

else里面调用了setValue方法,我们再继续跟下去 (哈哈,感觉好像捉贼一样):


private void setValue(int propertyConstant, float value) {
       final View.TransformationInfo info = mView.mTransformationInfo;
       final RenderNode renderNode = mView.mRenderNode;
       switch (propertyConstant) {
           case TRANSLATION_X:
               renderNode.setTranslationX(value);
               break;
           case TRANSLATION_Y:
               renderNode.setTranslationY(value);
               break;
           case TRANSLATION_Z:
               renderNode.setTranslationZ(value);
               break;
           case ROTATION:
               renderNode.setRotation(value);
               break;
           case ROTATION_X:
               renderNode.setRotationX(value);
               break;
           case ROTATION_Y:
               renderNode.setRotationY(value);
               break;
           case SCALE_X:
               renderNode.setScaleX(value);
               break;
           case SCALE_Y:
               renderNode.setScaleY(value);
               break;
           case X:
               renderNode.setTranslationX(value - mView.mLeft);
               break;
           case Y:
               renderNode.setTranslationY(value - mView.mTop);
               break;
           case Z:
               renderNode.setTranslationZ(value - renderNode.getElevation());
               break;
           case ALPHA:
               info.mAlpha = value;
               renderNode.setAlpha(value);
               break;
       }
   }

我们可以看到,它就调用了View的mRenderNode里面的setXXX方法,最关键就是这些方法啦,其实这几个setXXX方法在View里面也有公开的,我们也是可以直接调用的,所以我们在处理ACTION_MOVE的时候,就直接调用它而不用播放动画啦。我们现在验证一下这个方案可不可行:先试试setTranslationY:

Android之ArcSlidingHelper制作圆弧滑动效果

将setTranslationY方法换成setRotation看看:

Android之ArcSlidingHelper制作圆弧滑动效果

来源:https://blog.csdn.net/u011387817/article/details/80313184

标签:Android,弧形,滑动,ArcSlidingHelper
0
投稿

猜你喜欢

  • Java经典面试题最全汇总208道(四)

    2023-11-08 23:59:26
  • Windows 10上JDK环境安装配置图文教程

    2023-05-31 19:38:03
  • java读取文件内容,解析Json格式数据方式

    2021-10-07 13:56:23
  • C#把数组中的某个元素取出来放到第一个位置的实现方法

    2021-11-26 00:17:36
  • c#网络唤醒功能实现

    2022-07-03 03:26:51
  • Android开发之DatePickerDialog、TimePickerDialog时间日期对话框用法示例

    2022-10-25 21:21:12
  • SpringBoot参数校验Validator框架详解

    2023-09-22 07:08:40
  • Android自定义Toast之WindowManager

    2022-10-27 09:13:10
  • 深入理解Java高级特性——注解

    2021-05-23 20:28:54
  • C# winform 请求http的实现(get,post)

    2023-03-20 13:52:01
  • Java C++ 算法题解leetcode1608特殊数组特征值

    2023-05-21 21:09:01
  • 解决SpringMVC拦截器path路径的坑

    2023-03-24 17:02:01
  • OpenGL画bezier曲线

    2021-11-30 19:09:06
  • C# Winform消息通知之系统本地通知local toast notification

    2023-02-01 04:14:02
  • Java 遍历取出Map集合key-value数据的4种方法

    2022-02-03 02:48:59
  • 如何解决springmvc文件下载,内容损坏的问题

    2023-10-11 07:12:10
  • 解析spring加载bean流程的方法

    2023-11-29 13:50:32
  • 通过Java修改游戏存档的实现思路

    2023-07-30 20:10:55
  • 半小时实现Java手撸网络爬虫框架(附完整源码)

    2022-11-23 15:59:35
  • spring data jpa如何使用自定义repository实现类

    2023-05-31 07:41:17
  • asp之家 软件编程 m.aspxhome.com