PathMeasure 轨迹动画神器 路径动画
PathMeasure 轨迹动画神器
轨迹动画一般利用SVG来实现,或者使用属性动画,自定义估计值,根据两点之间的线性关系式计算坐标(复杂)
但是使用PathMeasure来进行绘制轨迹动画,so easy。
先看效果:
效果分析:
1、圆圈变成圆弧
2、圆弧不断的变小
实现
方式1:通过不断改变绘制圆弧的开始角度。 这个方法肯定是最先想到的方法,
因为api
drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
@NonNull Paint paint)用的最多
方式2:利用PathMeasure,不断截取路径。截取不断变小的圆弧,然后把截取到的path绘制出来就可以。
比较:两种方式相比PathMeasure并没有多大的优势,但是绘制圆弧可以使用 drawArc 来改变角度实现类似轨迹运动的效果,但是,如果path、不是一个圆形,问题就复杂了,PathMeasure的强大也就体现出来了。
学习PathMeasure的使用
查看源码,发现只有100多行,其实也就几个方法。但是确实非常流弊
1、setPath(Path path, boolean forceClosed)
要对path进行操作,首先需要设置一个path,也可以在构造函数中绑定,关键在第二个参数,是否关闭,如果是true,那么会给参数path,强制首尾闭合,因为path可能是一个非闭合的路径。
2、getLength
得到path路径的长度,很有用。
3、getPosTan(float distance, float pos[], float tan[])
得到distance,位置的点的坐标,和在个点与path进行切线的正切,分别放在pos[] 和tan[]中。
例如,distance==length/2,就是得到这条path路径的中间点,的坐标和正切
4、getMatrix(float distance, Matrix matrix, int flags)
这个就厉害了,直接返回得到矩阵,这个矩阵就包含了这个点移动的位置,和倾斜的角度,可以直接在这个点绘制
一个图片,利用这个matrix
5、getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)
从开始的距离,到结束的距离,截取一段path放在dst中,
startWithMoveTo 如果为true,这个dst会从截取点开始
如果为false,这个dst会从(0,0)作为开始点
使用PathMeasure来进行分析
接着圆弧动画完了,就是手柄的动画。把属性动画的0到1拆分,0到0.8,完成画的轨迹动画,0.8到1完成手柄的动画,手柄就是一条直线,再使用PathMeasure有点大炮打蚊子,直接不断改变手柄直线的结束点就可以了。
下面是具体的代码实现:
package com.lmj.searchview;import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;/*** Created by limengjie* on 2017/5/25.14:37*/public class SearchView extends View {private Matrix mMatrix;private Paint mPaint;private Path mPath;private int mCircleX;private int mCircleY;private int mRadius = 50;//圆的半径private PathMeasure mPathMeasure;private float circleLength;private float startD;private float endD;private ValueAnimator mvalueAnimator_rotate;private ValueAnimator mvalueAnimator_path;private String Tag = "SearchView";private Path dstCircle;private int lineD = 0;private static final int Status_Normal = 1;//正常状态private static final int Status_PathAni = 2;//正在进行轨迹动画private static final int Status_RotateAni = 3;//正在旋转动画private int Status = Status_Normal;private int rotateNum;public SearchView(Context context) {this(context, null);init();}public SearchView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init();}private void init() {mMatrix = new Matrix();mPaint = new Paint();mPath = new Path();mPaint.setStyle(Paint.Style.STROKE);mPaint.setColor(Color.GREEN);mPaint.setStrokeWidth(2);mPaint.setAntiAlias(true);mPathMeasure = new PathMeasure();dstCircle = new Path();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);mPath.reset();mCircleX = getWidth() / 2;mCircleY = getHeight() / 2;switch (Status) {case Status_Normal:drawNormal(canvas);break;case Status_PathAni:drawPathAni(canvas);break;case Status_RotateAni:drawRotateAni(canvas);break;}}private void drawNormal(Canvas canvas) {mPaint.setColor(Color.GREEN);mPath.addCircle(mCircleX, mCircleY, mRadius, Path.Direction.CW);canvas.save();canvas.drawPath(mPath, mPaint);canvas.rotate(45, mCircleX, mCircleY);canvas.drawLine(mCircleX + mRadius, mCircleY, mCircleX + mRadius * 2, mCircleY, mPaint);canvas.restore();}private void drawPathAni(Canvas canvas) {mPath.addCircle(mCircleX, mCircleY, mRadius, Path.Direction.CW);canvas.save();canvas.rotate(45, mCircleX, mCircleY);mPathMeasure.setPath(mPath, false);circleLength = mPathMeasure.getLength();endD = circleLength;dstCircle.reset();Log.i(Tag, "sd:" + startD + ",ed:" + endD);mPathMeasure.getSegment(startD, endD, dstCircle, true);
// mPaint.setColor(Color.RED);canvas.drawPath(dstCircle, mPaint);//圆的动画canvas.drawLine(mCircleX + mRadius, mCircleY, mCircleX + mRadius * 2 - lineD, mCircleY, mPaint);canvas.restore();}private void drawRotateAni(Canvas canvas) {mPath.addCircle(mCircleX, mCircleY, mRadius, Path.Direction.CW);canvas.save();canvas.rotate(45+rotateNum, mCircleX, mCircleY);mPathMeasure.setPath(mPath, false);circleLength = mPathMeasure.getLength();dstCircle.reset();mPathMeasure.getSegment(0, 20, dstCircle, true);
// mPaint.setColor(Color.RED);canvas.drawPath(dstCircle, mPaint);//圆的动画}private void startPathAni() {
// if(null==mvalueAnimator){if (null != mvalueAnimator_path) {mvalueAnimator_path.cancel();}lineD = 0;mvalueAnimator_path = ValueAnimator.ofFloat(0, 1);mvalueAnimator_path.setDuration(1500);mvalueAnimator_path.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {//0-0.8,分割圆,0.8到1 分割手柄float fraction = animation.getAnimatedFraction();if (fraction <= 0.8f) {startD = circleLength * fraction / 0.7f;} else {startD = circleLength;lineD = (int) ((fraction - 0.8) * mRadius / 0.2f);}if(fraction==1f){lineD = mRadius;Status = Status_RotateAni;postInvalidate();startRotateAni();}postInvalidate();}});mvalueAnimator_path.start();
// }}public void startRotateAni(){if (null != mvalueAnimator_rotate) {mvalueAnimator_rotate.cancel();}mvalueAnimator_rotate = ValueAnimator.ofInt(0, 360,0);mvalueAnimator_rotate.setDuration(3000);mvalueAnimator_rotate.setRepeatMode(ValueAnimator.RESTART);mvalueAnimator_rotate.setRepeatCount(-1);mvalueAnimator_rotate.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {rotateNum = (int) animation.getAnimatedValue();postInvalidate();}});mvalueAnimator_rotate.start();}public void startSearch() {Status = Status_PathAni;startPathAni();postInvalidate();}public void stopSearch() {Status = Status_Normal;if (null != mvalueAnimator_rotate) {mvalueAnimator_rotate.cancel();}if (null != mvalueAnimator_path) {mvalueAnimator_path.cancel();}postInvalidate();}}
总结,
只要我们有一个已知的path,就可以通过PathMeasure,来截取轨迹,根据距离来获取某个点的坐标和正切,所以有了path,轨迹动画就so easy了。
源码下载
————————————————
版权声明:本文为CSDN博主「按劳分配」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lmj121212/article/details/72736316
PathMeasure 轨迹动画神器 路径动画相关推荐
- Threejs开发之移动动画、旋转动画、缩放动画和路径动画
以下代码 示例了threejs的移动动画.旋转动画.缩放动画和路径动画 注意:引入three.js三维引擎的路径需要根据 自己的情况修改相应的路径,本示例采用引用外部模块的方式. 以下为完整代码: & ...
- SVG—初识4之描边动画和路径动画
SVG-初识4 SVG描边动画 stroke-dashoffset DrawSVGPlugin插件 路径动画 CSS写路径动画 SVG写路径动画 使用 GreenSock 来实现自行车沿着路径运动的路 ...
- WPF 动画之路径动画DoubleAnimationUsingPath
虽然一直在做WPF开发, 但是实际项目中很少用到动画,今天突然想要撸一撸, 于是便有了下面的代码 <Window.Resources><PathGeometry x:Key=&qu ...
- android svg路径动画,Svg 路径动画实现旋转进度条
尝试使的候通现端数是制这.效合应近环大过这业据用 Svg 实现简易的动画效果.有关 Svg 的具体知识点不在此文赘述,仅就所举示例的需求点阐述实在重说道.础过学开概码数项遍间里哦行览屏屏定处..容标中 ...
- 三维场景中常用的路径动画
三维场景中常用的路径动画 前言 在三维场景中,除了用逼近真实的模型代表现实中的设备.标识物外,通常还会使用一些动画来表示模型在现实中一些行为和作用.常见的动画比如路径动画.旋转动画.发光动画.流动动画 ...
- osgEarth AnimationPath路径动画
目录 飞机飞行实例 路径动画暂停 路径动画继续 osgEarth 视角跟踪飞机飞行 相机跟踪飞机移动 视角移动到特定地点 osg::AnimationPath 封装了一个随时间变化的过程,可以用来更新 ...
- 咸鱼Maya笔记—路径动画
咸鱼Maya笔记-路径动画 创建路径动画 动画的创建方式有很多种,路径动画是其中的一种,Key关键帧的方式并不适用于所有的情况,有些特定的情况下我们就需要用到路径动画,它的创建方法如下 创建路径动画 ...
- android文字轨迹动画,文字转化为路径动画 TextPathView
介绍 大家新年快乐,TextPathView是一个把文字转化为路径动画然后展现出来的自定义控件.效果如上图: 使用 主要的使用流程就是输入文字,然后设置一些动画的属性,还有画笔特效,最后启动就行了. ...
- 【Python应用】Python+Kepler.gl轻松制作酷炫路径动画
文章来源于Python大数据分析,作者费弗里 本文示例代码.数据已上传至Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 ...
最新文章
- python多线程编程(2): 使用互斥锁同步线程
- 全球及中国自卸车行业深度分析与“十四五”发展战略规划研究报告2022-2028年版
- python求最大连续子数组
- 如何突破Windows环境限制打开“命令提示符”
- 深入理解JVM虚拟机读书笔记【第十三章】线程安全与锁优化
- ai中如何插入签名_如何在PDF文档中插入文本框?
- 史上最烂 spring aop 原理分析
- halcon程序安装破解与VC6.0结合
- 如果你的天猫魔盒不能看了
- 如何完整的修改一个数据库的名称
- SpringBoot2.x 监听器详解
- 解决WiFi网速慢和防蹭笔记
- 应用深度学习function-loss-optimization 2020.8.24
- 使用anaconda 要用conda 方式更新各个软件,不要用pip
- windows驱动开发5:WDK Demo:avstream avscamera
- 使用vue+echarts快速进行全国地图与各省市地图联动(下钻地图), 引入省份js文件
- 【计算机视觉】INRIA 行人数据集 (INRIA Person Dataset)
- D-LINK DI-504路由器TELNET方法及命令运行查看方式
- 格斗手游服务器语言,steam上的油腻师姐移植手机,这是部有点“色”的横版格斗 新游酱每日游戏推荐...
- esxi license过期_Vcenter 和ESXi License过期解决办法