软件编程
位置:首页>> 软件编程>> Android编程>> Android之ArcSlidingHelper制作圆弧滑动效果

Android之ArcSlidingHelper制作圆弧滑动效果

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

标签:Android,弧形,滑动,ArcSlidingHelper

前言

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

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

  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

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com