Android之ArcSlidingHelper制作圆弧滑动效果
作者:陈小缘 发布时间:2021-07-23 03:10:24
前言
我们平时在开发中,难免会遇到一些比较特殊的需求,就比如我们这篇文章的主题,一个关于圆弧滑动的,一般是比较少见的。其实在遇到这些东西时,不要怕,一步步分析他实现原理,问题便能迎刃而解。
前几天一位群友发了一张图,问类似这种要怎么实现:
要支持手势旋转
旋转后惯性滚动
滚动后自动选中
哈哈, 来一张自己实现的效果图:
初步分析
首先我们看下设计图,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);
可以看到,在View位移之后,监听点击事件的区域还是在原来的地方。我们再看下用属性动画的:
mView.animate().translationX(150).translationY(300).setDuration(500).start();
监听点击事件的区域随着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:
将setTranslationY方法换成setRotation看看:
来源:https://blog.csdn.net/u011387817/article/details/80313184


猜你喜欢
- 本文实例讲述了java实现的五子棋游戏代码,分享给大家供大家参考,具体代码如下package gyb.exam;import java.aw
- 前言在日常的开发中StringBuilder大家肯定都有用过,甚至用的很多。毕竟大家都知道一个不成文的规范,当需要高频的大量的构建字符串的时
- LiveData简介在日常安卓开发中,一些耗时的 * 如列网络请求,数据库读写都不能在主线程执行,必须开一条子线程去执行这些耗时操作,但我们往
- WebService服务端代码public class WebServiceDemo : System.Web.Services.WebSe
- 前言以下为本文要记录的大概内容:Java基础案例:两只老虎、三个和尚、考试奖励以下是本篇文章正文内容,仅供参考一、案例1:两只老虎1.题目:
- 实践过程效果代码public partial class Form1 : Form{ public Form1()
- 问题描述提交表单到servlet时出现空白页面,但又网站不报错截图如下遇到这个问题查找了很多,仍没有解决,刚开始接触IDEA,以为是路径配置
- System.Web.Caching.Cache Insert和Add方法的区别Add()object Add(string key, ob
- 新建Rest服务接口:[ServiceContract]public interface IService1{ &nb
- 一、创建一个cs文件,定义Time 对象 public class WebTimer_AutoRepayment{ &n
- package com.test.html;import com.alibaba.fastjson.JSON;import org.apac
- 我们在使用数据库进行查询时,很多时候会用到分页展示功能,因此除了像mybatis这样的完善的orm框架之外,还有pagehelper这样的插
- 垃圾回收器要回收对象的时候,首先要调用这个类的finalize方法(你可以 写程序验证这个结论),一般的纯Java编写的Class不需要重新
- using System;using System.Collections.Generic;using System.ComponentMo
- JenkinsJenkins是一个开源的、可扩展的持续集成、交付、部署的基于web界面的平台。允许持续集成和持续交付项目,无论用的是什么平台
- 本文实例讲述了C#数据结构之队列(Quene)。分享给大家供大家参考,具体如下:队列(Quene)的特征就是“先进先出”,队列把所有操作限制
- 本篇主要描述“发送邮箱验证码、session校验”相关前(html\js)后(java)台代码,业务逻辑示例,闲话少诉,直接上代码。1、引入
- public static void main(String args[]) {Map<String, Object> map
- 场景点击拨打电话按钮,跳转到拨打电话页面点击发送短信按钮,跳转到发送短信页面注:实现将布局改为LinearLayout,并通过android
- Android开发中,当一个页面存放的控件超出屏幕时,通常需要使用ScrollView来包裹布局。这样用户可以通过手指的滑动来查看超出屏幕的