平时用path画一些简单的几何图形,呈现的时候也是已经绘制好的图形,想想,如果像动画一样看到它的绘制轨迹,是不是更酷?今天介绍的这个类PathMeasure就是干这个的,知道它的存在还是由于看了启舰写的的自定义控件那本书。好,进入正题。

  先说说Path,当你设置画笔是描边模式时,你绘制的Path可以看做一条条连续不断的线段首尾相连。当你设置画笔是填充模式时,你绘制一个起点和终点,path是绘制不出来的(除非你绘制3个点)。所以在使用路径跟踪的前提,先把画笔设为描边模式,因为画笔默认的样式是填充模式,这是第一个注意事项。在使用PathMeasure时,对它的理解越简单通透,你就会知道,用它需要准备哪些变量,变量全部初始完毕,用起来就像照葫芦画瓢一样简单!

  PathMeasure和一个你绘制好的完整path绑定,然后,你可以随意设置起点和终点,得到两点之间的path,得到这个path怎么用呢,你是不是会这么想:我有一条线段,分成10等份,我每次更正起点和终点,取0-1,1-2,2-3...这些片段路径来绘制!不用那么麻烦的,你可以直接把起点固定为0,逐渐修正终点,这样你会得到0-1,0-2,0-3...的path。然后交给canvas去绘制就行了,因为canvas在3个10毫秒分别绘制0-1,0-2,0-3,它看起来就是30毫秒内从0-3的完整轨迹。这个过程就类似scrollTo。接下来,看看常用的3个方法:

   public PathMeasure(Path path, boolean forceClosed) {
// The native implementation does not copy the path, prevent it from being GC'd
mPath = path;
native_instance = native_create(path != null ? path.readOnlyNI() : 0,
forceClosed);
}

1.第一个参数就是你要跟踪的path,第二个参数强制关闭,表示是否把你传入的第一个path当做全封闭路径处理。举个例子:

假如pathMeasure传的第一个path,是用3条线段绘制的,如左图,每段长为50px,那么pathMeasure构造方法的forceClose为true时,它把你的传入的path当做全封闭路径处理,也就是当初第二张图,这时pathMeasure.genLength()获取的路径就是50*4;如果forceClose设为false,那么它还是当做path原始的路径,该几条线就几条线,pathMeasure获取的路径长就是50*3。所以,建议构造的pathMeasure,直接设为false,保持原始路径的模样。

  第二个方法就是最常用的截取一段path的方法:

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

  前两个参数一目了然,不多介绍,有意思的是后面两位。第3个dst,就是用来接收截取完之后的desPath,第4个参数的true和false,将直接影响desPath。考虑一下这种情况,假如desPath初始化时就已经添加了一段路径,如(0,0)到(50,50),这是一条斜线。那么之后getSegment方法走完,desPath新增的截取path的起点和终点分别为(100,0)和(100,100),新path怎么个添加法呢?这就是startWithMoveTo()这个方法决定的,它为true:好,绘制完(0,0)到(50,50)之后,系统帮你调一次moveTo(x,y),绘制起点直接挪到截取path的起点上,如左图。如果为false:绘制完(0,0)到(50,50)之后,系统帮你调一次lineTo(x,y),把最开始的path尾巴和我新截取的path头给首尾相连,如右图。说的已经很详细了,再来张手绘图,应该一目了然了。

  第3个方法很简单的,它的作用就是切换路径轮廓,假如我画了一个圆,我下一条路径在圆里面,可不是在圆周上,怎么办,调它就行了,此时你会发现pathMeasure.getLength()也会重置为你新路径轮廓的长度.

public boolean nextContour()

  方法讲完,实战写个看看。这里我画的还是从书里看的那个支付完成控件,因为我就是看懂了这个控件,才逐渐能画出五角星,搜索框这样的图标。所以,我还是愿意把启舰写的这个简单却又涉及全面的例子再分享给大家。这里上传的是静态图,实际上是动态的,自己写个demo可以看到绘制过程。

public class AiliPayView extends View {
private Paint paint;
private Path path,desPath;
private PathMeasure pathMeasure;
private ValueAnimator valueAnimator;
private float curValue;
private boolean isNext = false; public AiliPayView(Context context) {
super(context);
init();
} public AiliPayView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
} public AiliPayView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
} private void init(){
setLayerType(LAYER_TYPE_SOFTWARE, null);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(8);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLACK);
path = new Path();
desPath = new Path();
} @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
path.addCircle(w/2,h/2,w/2-4, Path.Direction.CW);
path.moveTo(w/4,h/2);
path.lineTo(w/2,h/4*3);
path.lineTo(w/4*3,h/4); pathMeasure = new PathMeasure(path, false);
valueAnimator = ValueAnimator.ofFloat(0,2);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
curValue = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.setDuration(3000);
valueAnimator.start();
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (curValue < 1){
float stop = pathMeasure.getLength() * curValue;
pathMeasure.getSegment(0,stop,desPath,true);
}else {
if (!isNext){
isNext = true;
//这里是临界状态,getlength是圆的总长
pathMeasure.getSegment(0, pathMeasure.getLength(), desPath, true);
//路径轮廓切换
pathMeasure.nextContour();
}else {
//getlength是新轮廓的总长,还有true的设置,因为折线路径在圆里面,所以把绘制起点更换,否则,折线的起点和圆又会连起来
                float stop = pathMeasure.getLength() * (curValue - 1);
pathMeasure.getSegment(0, stop, desPath, true);
}
}
canvas.drawPath(desPath,paint);
}
}

代码中有些细节值得注意:

  1.在获取中画圆时,圆心选取没什么问题,半径的设置可能需要根据长宽不一致,进一步的确认,我这里默认长宽是相等的写法。另外,我设置的圆半径为w/2-4,为什么要减4呢?因为画笔的描边宽度我设置的是8,当我不减去画笔宽度的一半时,你可以发现最终的绘制的圆于控件区域相切的4个点,都会显得细一点。你可以想象,画笔的笔尖宽度为8,以它中点扫去,刚好一半的宽度超出的显示区域,所以,半径减去画笔一半的宽度。

  2.从圆路径切换到折线路径,用isNext这个标识。因为我们的值动画是匀速的,值区域在(0,2),可以保证监听值在<1时,控件还在画圆,那我们可以认为监听值等于1,就是圆刚好结束吗?其实是无法保证的,因为不断改变的curValue可能是从0.99直接到1.01,它不一定等于1的。 所以我们在curValue 》=1 的第一时间,我们绘制完整个圆路径,然后切换路径轮廓,pathMeasure.getLength()就从圆周长 变成了折线的长度。这也是后来的getSegment()的终点值(curValue - 1)的原因。

路径跟踪 PathMeasure的简单使用的更多相关文章

  1. 无人驾驶车辆路径跟踪的增量式PID控制

    路径跟踪是无人车研究方向的一项关键技术.路径跟踪控制算法是指能够使无人车按照预设路径,安全稳定行驶的控制方法. 建立无人车路径跟踪模型 预设无人车在A.B两点间,当前位置为D点,航向为hF 可以得到B ...

  2. hdoj 5092 Seam Carving 【树塔DP变形 + 路径输出】 【简单题】

    Seam Carving Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Tot ...

  3. TaintDroid剖析之DVM变量级污点跟踪(下篇)

    TaintDroid剖析之DVM变量级污点跟踪(下篇)作者:简行.走位@阿里聚安全 ​ 1 回顾 在上一章节中我们详细分析了TaintDroid对DVM方法参数和方法变量的变量级污点跟踪机制,现在我们 ...

  4. Java EE 编程中路径

    版权声明:未经博主允许,不得转载 首先我们要限定一个范围,是一个项目,或是以个访问地址..就先以一个项目为限定的范围 前述: 学过物理学的都知道相对运动和绝对运动, 虽然是相似的概念,但这里的要简单得 ...

  5. 【Spring】搭建最简单的Spring MVC项目

    每次需要Spring MVC的web项目测试一些东西时,都苦于手头上没有最简单的Spring MVC的web项目,现写一个. > 版本说明 首先要引入一些包,Spring的IOC.MVC包就不用 ...

  6. [MAC] 在标题栏上显示目录完整路径

    转载自 :http://www.cnblogs.com/yipu/archive/2013/03/13/2956957.html 当我们使用Finder浏览文件的时候,当前目录的名字会显示在标题栏顶端 ...

  7. 资源 之 4.4 Resource通配符路径(拾贰)

    4.4.1  使用路径通配符加载Resource 前面介绍的资源路径都是非常简单的一个路径匹配一个资源,Spring还提供了一种更强大的Ant模式通配符匹配,从能一个路径匹配一批资源. Ant路径通配 ...

  8. GET请求和POST请求简单说明

    一.概述 * HTTP/1.1协议共定义了8中请求方法:OPTIONS, HEAD, GET, POST, PUT, DELETE, TRACE, CONNECT. * GET方法和POST是我们使用 ...

  9. 资源 之 4.4 Resource通配符路径 ——跟我学spring3

    4.4.1  使用路径通配符加载Resource 前面介绍的资源路径都是非常简单的一个路径匹配一个资源,Spring还提供了一种更强大的Ant模式通配符匹配,从能一个路径匹配一批资源. Ant路径通配 ...

随机推荐

  1. Mysql5.7及以上版本 ONLY_FULL_GROUP_BY报错

    近期在开发过程中,因为项目开发环境连接的mysql数据库是阿里云的数据库,而阿里云的数据库版本是5.6的.而测试环境的mysql是自己安装的5.7.因此在开发过程中有小伙伴不注意写了有关group b ...

  2. 环境篇:VMware Workstation安装Centos7

    环境篇:VMware Workstation安装Centos7 1 VMware Workstation安装 CentOS下载地址:http://isoredirect.centos.org/cent ...

  3. tarjan算法强连通分量的正确性解释+错误更新方法的解释!!!+hdu1269

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1269 以下内容为原创,转载请声明. 强连通分量SCC(Strongly Connected Compo ...

  4. 第十周Java实验作业

    实验十  泛型程序设计技术 实验时间 2018-11-1 1.实验目的与要求 (1) 理解泛型概念: 泛型:也称参数化类型,就是在定义类,接口和方法时,通过类型参数只是将要处理的类型对象.(如Arra ...

  5. [模板] trie树 (字典树)

    本文基于https://www.cnblogs.com/TheRoadToTheGold/p/6290732.html #include<bits/stdc++.h> using name ...

  6. Python——迭代器的几个高级用法

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第8篇文章. 今天我们依然介绍的是迭代器,不过介绍的是几个比较常用的高级用法,在实际场景当中非常实用,可以帮助我们大 ...

  7. windows常用系统命令

    dir指定要列出的驱动器.目录和/或文件 显示当前路径下的所有文件的绝对路径,包含子文件夹中的内容 dir /b / s /o:n /a:a /b 表示去除摘要信息,且顶格显示完整路径 /s 表示枚举 ...

  8. office的高级应用

    Word高级应用:设置斜线表头(一根:边框:多根:插入形状,按住鼠标拖动). 注意:1.用好样式功能 2.大量重复工作懂得批量处理 3.反复要做的固定操作固化成“模板”“套路” 4.碰到异常情况,知道 ...

  9. class字节码的结构

    class字节码的结构 使用javap -verbose 命令分析一个.class字节码文件时(以下简称字节码文件),将会分析该字节码文件的魔数,版本号,常量池,类信息,类的构造方法,类中的方法信息, ...

  10. Python python lamda 表达式

    '''关键字lambda表示匿名函数,冒号前面的x表示函数参数. 匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果. 用匿名函数有个好处,因为函数没有名字,不必担心 ...