Android自定义控件开发入门与实战(6)路径动画,android脚本开发工具

前面几章所讲的内容其实都只是比较普通、简单的动画,这章开始学习较难、较为有深度、也比较可以实现更加炫酷效果的动画,通过PathMeasure和SVG动画来实现。

PathMeasure实现路径动画


PathMeasure是Android官方API,是之前第一张关于路径只是的一个扩展,十分的有用。

PathMeasure可以计算出路径的总长、指定长度所对应的坐标等等路径信息。

有两种初始化方式:

第一种:

PathMeasure pathMeasure = new PathMeasure();

直接new一个,然后接下来通过PathMeasre的setPath()绑定PathMeasure和Path

setPath(Path path,boolean forceClosed)

这样就完成初始化,接着就可以用pathMeasure来调用关于路径的信息辽。

第二种方法:

直接通过PathMeasure构造方法初始化。

PathMeasure(Path path,boolean forceClosed);

这两种方法都会涉及到的forceClosed是计算path是否闭合,但是path的闭合并不是由forceClosed控制,绘制出来时,path该闭合还是闭合,不闭合就是不闭合,但是如果forceClosed设置为true时,会当做path闭合,把闭合的路径算进去。

一些简单的函数使用

1、getLength()

public float getLength()

该函数的作用为计算路径长度,使用非常广泛。

我们用路径来画一个没有闭合的正方形:

canvas.translate(50, 50);

Path path = new Path();

path.moveTo(0, 0);

path.lineTo(0, 100);

path.lineTo(100, 100);

path.lineTo(100, 0);

PathMeasure pathMeasure1 = new PathMeasure(path, false);

PathMeasure pathMeasure2 = new PathMeasure(path, true);

Log.e(TAG, "forceClose = false : " + pathMeasure1.getLength());

Log.e(TAG, "forceClose = true : " + pathMeasure2.getLength());

canvas.drawPath(path,paint);

在这里插入图片描述

打出的第一个Log长度为300,而第二个则为400.因为第二个已经考虑到闭合了。

2、isClose()

判断测量的path是否闭合。

如果PathMeasurei的forceClosed设置为true时,则isClosed()一定为true

3、nextContour()

Path可以有很多曲线、线段构成,但是getLength()只会取第一条线进行计算。

而nextContour()是跳转到下一条曲线的函数。如果跳转成功则返回true,否则返回false。

注:pathMeasure.getLength()只针对第一条曲线

getSegment

用法

boolean getSegment(float startD,float stopD,Path dst,boolean startWithMoveTo);

顾名思义,这个函数用截取一个Path中的某一个片段。

通过参数startD和stopD来控制截取的长度。并将截取后的Path保存到参数dst中。

最后一个参数startWithMoveTo表示起始点是否使用moveTo将路径的新起始点移到结果Path的起始点,通常设置为true。用来保证每次截取segment都是连续的、完整的。

  • 其中startD为开始截取位置距离Path起点的长度,stopD为结束时截取位置距离Path起点的长度。如果startD和stopD的范围不再Path的长度范围内或者 startD==stopD该函数返回false

  • 如果在开启硬件加速并使用该方法,绘图会出现问题,所以在使用getSegment时要禁用硬件加速。

这里来截取一个path,代码如下:

canvas.translate(100, 100);

Path path = new Path();

path.addRect(-50,-50,50,50, Path.Direction.CW);

Path dst = new Path();

PathMeasure pathMeasure = new PathMeasure(path, false);

pathMeasure.getSegment(0,150,dst,true);

canvas.drawPath(dst, paint);

截取的path如下

在这里插入图片描述

这说明截取是左上角开始截取,并且方向是根据Path的绘制方向截取,上面path绘制是CW(顺时针),所以截取了上半部分。

如果dst本来就已经是一个路径,这个时候再去取别的path的路径,会怎么样呢?

答案是 原来的路径不会被覆盖,反而和新的截取到的路径一起绘制出来。

如下图所示:

在这里插入图片描述

如果这个时候我们把 PathMeasure的startWithMoveTo改为false会怎么样呢?下过如下所示:

在这里插入图片描述

这里咋一看不是很好理解,其实画个图就ok,因为startWithMoveTo设置为false就是将新的Path的起始点拉到自己原本dst的结束点(因为dst自己画的是不能变的) ,然后目标path其他位置的点不变

就像是使用processon、viso软件画图的时候,用一条线的起点去连另一条线的终点这样。

示例

路径绘制是PathMeasure最常用的功能,下面实现一个转圈圈的加载效果图。

思路是通过ValueAnimator动画算出当前的动画的进度,通过进度获取转圈圆的周长,拿到周长后通过PathMeasure的getLength和getSegment去画圆。

我们再构造函数中做new的操作:

public PathMeasureView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

paint = new Paint(Paint.ANTI_ALIAS_FLAG);

setLayerType(LAYER_TYPE_SOFTWARE, null);

paint.setStrokeWidth(4);

paint.setStyle(Paint.Style.STROKE);

paint.setColor(Color.RED);

dst = new Path();

circlePath = new Path();

circlePath.addCircle(100, 100, 50, Path.Direction.CW);

pathMeasure = new PathMeasure(circlePath, true);

ValueAnimator animator = ValueAnimator.ofFloat(0, 1);

animator.setRepeatCount(ValueAnimator.INFINITE);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

drawProgress = (float) animation.getAnimatedValue();

invalidate();

}

});

animator.setInterpolator(new AccelerateInterpolator());

animator.setDuration(2000);

animator.start();

}

之后再draw函数中做下面的操作:

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.drawColor(Color.WHITE);

float stop = pathMeasure.getLength() * drawProgress;

dst.reset();

pathMeasure.getSegment(0, stop, dst, true);

canvas.drawPath(dst, paint);

}

最后效果如下所示:

在这里插入图片描述

但是这个加载圈的起点一直在画圆的起点,和我们平时看到的加载圆有点不一样,所以我们可以去改变它的起始点,来让圆更加生动:

当动画开始到一半的时候,起点都是最开始的画圆的起点,到后半段,dst圆的起始点开始逐渐向结束点靠拢,最后到达开始位置的时候,两个端点重合

可以得出当

  • 进度drawProgress< 0.5时 startD=0

  • 进度drawProgress>0.5时 startD=(2*drawProgress-1)*length

  • 通过合并公式可以得出 startD = stopD - (0.5 - |drawProgress - 0.5| )*length

float start = (float) (stop - (0.5 - Math.abs(drawProgress - 0.5)) * pathMeasure.getLength());

pathMeasure.getSegment(start, stop, dst, true);

canvas.drawPath(dst, paint);

这就很顶啦。

在这里插入图片描述

getPosTan()

getPosTan()函数用于得到路径上某一长度的位置以及该位置的正切值。

boolean getPosTan(float distance ,float[]pos,float[]tan);

  • float distance: 距离Path起始点的长度,取值范围为0≤distance≤getLength

  • float[]pos:该点的坐标值 pos[0]表示x坐标 pos[1]表示y坐标

最后

简历首选内推方式,速度快,效率高啊!然后可以在拉钩,boss,脉脉,大街上看看。简历上写道熟悉什么技术就一定要去熟悉它,不然被问到不会很尴尬!做过什么项目,即使项目体量不大,但也一定要熟悉实现原理!不是你负责的部分,也可以看看同事是怎么实现的,换你来做你会怎么做?做过什么,会什么是广度问题,取决于项目内容。但做过什么,达到怎样一个境界,这是深度问题,和个人学习能力和解决问题的态度有关了。大公司看深度,小公司看广度。大公司面试你会的,小公司面试他们用到的你会不会,也就是岗位匹配度。

选定你想去的几家公司后,先去一些小的公司练练,学习下面试技巧,总结下,也算是熟悉下面试氛围,平时和同事或者产品PK时可以讲得头头是道,思路清晰至极,到了现场真的不一样,怎么描述你所做的一切,这绝对是个学术性问题!

面试过程一定要有礼貌!即使你觉得面试官不尊重你,经常打断你的讲解,或者你觉得他不如你,问的问题缺乏专业水平,你也一定要尊重他,谁叫现在是他选择你,等你拿到offer后就是你选择他了。

金九银十面试季,跳槽季,整理面试题已经成了我多年的习惯!在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

本文在开源项目:【GitHub 】中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…

真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-AypROxVr-1644997512950)]

本文在开源项目:【GitHub 】中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
封面 1 序 2 捐助说明 5 目 录 7 第一章 View的绘图流程 12 1.1、概述 12 1.2、Activity的组成结构 13 1.3、View树的绘图流程 15 1.3.1 测量组件大小 16 1.3.2 确定子组件的位置 17 1.3.3 绘制组件 18 1.4、说点别的 22 1.5 练习作业 22 第二章 Graphics2D API 23 2.1、概述 23 2.2、Point类和PointF类 23 2.3、Rect类和RectF类 25 2.4、Bitmap类和BitmapDrawable类 32 2.5、Canvas类与Paint类 34 2.5.1 绘图概述 34 2.5.2 Paint类 34 2.5.3 Canvas类 39 2.6 练习作业 63 第三章 使用Graphics2D实现动态效果 64 3.1 概述 64 3.2 invalidate()方法 65 3.3 坐标转换 69 3.4 剪切区(Clip) 73 3.5 案例:指针走动的手表 82 3.6 练习作业 88 第四章 双缓存技术 89 4.1 双缓存 89 4.2 在屏幕上绘制曲线 90 4.3 在屏幕上绘制矩形 99 4.4 案例:绘图App 104 4.4.1 绘图属性 106 4.4.2 软件参数 108 4.4.3 绘图缓冲区 109 4.4.4 撤消操作 111 4.4.5 图形绘制 113 4.4.6 绘图区 118 4.4.7 主界面 119 4.5 练习作业 122 第五章 阴影、渐变和位图运算 123 5.1 概述 123 5.2 阴影 123 5.3 渐变 125 5.3.1 线性渐变(LinearGradient) 126 5.3.2 径向渐变(RadialGradient) 130 5.3.3 扫描渐变(SweepGradient) 135 5.3.4 位图渐变(BitmapShader) 138 5.3.5 混合渐变(ComposeShader) 140 5.3.6 渐变与Matrix 142 5.4 位图运算 143 5.4.1 PorterDuffXfermode 143 5.4.2 图层(Layer) 146 5.4.3 位图运算技巧 148 5.5 案例1:圆形头像 152 5.6 案例2:刮刮乐 156 5.7 练习作业 161 第六章 自定义组件 163 6.1 概述 163 6.2 自定义组件的基本结构 164 6.3 重写onMeasure方法 166 6.4 组件属性 175 6.4.1 属性的基本定义 175 6.4.2 读取来自style和theme中的属性 181 6.5 案例1:圆形ImageView组件 186 6.6 案例2:验证码组件CodeView 190 6.7 练习作业 202 第七章 自定义容器 204 7.1 概述 204 7.2 ViewGroup类 205 7.2.1 ViewGroup常用方法 205 7.2.2 ViewGroup的工作原理 208 7.2.3 重写onLayout()方法 213 7.3 CornerLayout布局 217 7.3.1 基本实现 217 7.3.2 内边距padding 224 7.3.3 外边距margin 228 7.3.4 自定义LayoutParams 238 7.4 案例:流式布局(FlowLayout) 246 7.5 练习作业 256 第八章 Scroller与平滑滚动 257 8.1 概述 257 8.2 认识scrollTo()和scrollBy()方法 258 8.3 Scroller类 264 8.4 平滑滚动的工作原理 271 8.5 案例:触摸滑屏 272 8.5.1 触摸滑屏的技术分析 272 8.5.2 速度跟踪器VelocityTracker 273 8.5.3 触摸滑屏的分步实现 274 8.6 练习作业 285 第九章 侧边栏 287 9.1 概述 287 9.2 使用二进制保存标识数据 289 9.2.1 位运算符 289 9.2.2 位运算的常用功能 292 9.3 继承自ViewGroup的侧边栏 293 9.4 继承自HorizontalScrollView的侧边栏 304 9.5 练习作业 312 第十章 加强版ListView 313 10.1 概述 313 10.2 ListView的基本使用 314 10.3 ListItem随手指左右滑动 318 10.4 向右滑动删除ListItem 326 10.5 滑动ListItem出现删除按钮 336 10.5.1 列表项专用容器ExtendLayout 337 10.5.2 列表项能滑出删除按钮的ListView 342 10.5.3 定义布局文件 350 10.5.4 显示ListView 351 10.6练习作业 353 案例代码说明 354

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值