Android-高级-UI-进阶之路--(六)-PathMeasure-制作路径动画

//需要按下事件
MotionEvent.ACTION_DOWN -> return true
MotionEvent.ACTION_UP -> {
val rectF = RectF()
//计算 Path 边界
mPath.computeBounds(rectF, true)
//将边界放入矩形区域内
region.setPath(
mPath,
Region(rectF.left.toInt(), rectF.top.toInt(), rectF.right.toInt(), rectF.bottom.toInt())
)
if (region.contains(event.x.toInt(), event.y.toInt())) {
Toast.makeText(context, “点击了圆”, Toast.LENGTH_SHORT).show()
}
//用新的路径替换到当前路径所有内容
region.set(300, 800, 800, 1300)
if (region.contains(event.x.toInt(), event.y.toInt())) {
Toast.makeText(context, “点击了矩形”, Toast.LENGTH_SHORT).show()
}
}
}
return super.onTouchEvent(event)
}

  1. 效果

Path 我们就先学习到这里,该篇文章后面会有 Path 实战。

PathMeasure

上部分我们讲解了 Path 路径的知识,现在来看 Path 除了绘制图形好像也没什么作用,当然如果只是单纯显示 Path 绘制的图形,那我也就不介绍该篇的重点了。Android SDK 提供了一个非常有用的 API 来帮组开发者实现一个 Path 路径追踪,这个 API 就是 PathMeasure , 通过它可以实现复杂切绚丽的效果。

概念

PathMeasure 类似一个计算器,可以计算出指定路径的一些信息,比如路径总长、指定长度所对应的坐标点等。

API 使用

构造方法

//1.空参
public PathMeasure()
//2.path 代表一个已经完成的 Path,forceClosed 代表是否最后闭合
public PathMeasure(Path path, boolean forceClosed)

简单函数使用

  1. getLength() 函数

PathMeasure#getLength() 函数的使用非常广泛,其作用就是获取计算的路径长度,下面以一个例子来看下它的用法。

效果:

代码:

override fun draw(canvas: Canvas) {
super.draw(canvas)
/**

  • 1. getLength
    */
    //将起点移动到 100,100 的位置
    mPath.moveTo(100f,100f)
    //绘制连接线
    mPath.lineTo(100f,450f)
    mPath.lineTo(450f,500f)
    mPath.lineTo(500f,100f)
    mPathMeasure.setPath(mPath,false)//不被闭合
    mPathMeasure2.setPath(mPath,true)//闭合
    println(“forceClosed false pathLength = m P a t h M e a s u r e . l e n g t h " ) p r i n t l n ( " f o r c e C l o s e d t r u e p a t h L e n g t h = {mPathMeasure.length}") println("forceClosed true pathLength = mPathMeasure.length")println("forceClosedtruepathLength={mPathMeasure2.length}”)
    canvas.drawPath(mPath,mPathPaint)
    }

输出:

System.out: forceClosed false pathLength =1106.6663
System.out: forceClosed true pathLength =1506.6663

可以看见,如果 forceClosed 设置为 true/false 测量的是各自的 path 。

  1. isClosed() 函数

该函数用于判断测量 Path 时是否计算闭合。所以,如果在关联 Path 的时候设置 forceClosed 为 true ,那么这个函数的返回值也一定为 true.

  1. nextContour() 函数

我们知道,Path 可以由多条曲线构成,但无论是 getLength()、getSegment() 还是其它函数,都只会对针对其中第一条线段进行计算。而 nextContour 就是用于跳转到下一条曲线的函数,如果跳转成功,则返回 true ; 如果跳转失败,则返回 false.下面看一个示例,分别创建 3 条闭合 Path,然后利用 PathMeasure 来依次测量。

效果:

代码:

/**

  • 2. nextContour
    */
    mPath.addCircle(500f,500f,10f,Path.Direction.CW)
    mPath.addCircle(500f,500f,80f,Path.Direction.CW)
    mPath.addCircle(500f,500f,150f,Path.Direction.CW)
    mPath.addCircle(500f,500f,200f,Path.Direction.CW)

mPathMeasure.setPath(mPath,false)//不被闭合

canvas.drawPath(mPath,mPathPaint)

do {
println(“forceClosed pathLength =${mPathMeasure.length}”)
}while (mPathMeasure.nextContour())

输出:

2019-12-03 22:37:22.340 18501-18501/? I/System.out: forceClosed pathLength =62.42697
2019-12-03 22:37:22.341 18501-18501/? I/System.out: forceClosed pathLength =501.84265
2019-12-03 22:37:22.341 18501-18501/? I/System.out: forceClosed pathLength =942.0967
2019-12-03 22:37:22.341 18501-18501/? I/System.out: forceClosed pathLength =1256.1292

在这里,我们通过 do…while 循环和 measure.nextContour() 函数相结合,依次拿到 Path 中所有的曲线

通过这个例子我们可以知道,通过 PathMeasure#nextContour 函数得到的曲线顺序与 Path 添加的顺序相同

getSegment() 函数

//startD:开始截取位置距离 Path 起始点的长度
//stopD: 结束截取位置距离 Path 起始点的长度
//dst: 截取的 Path 将会被添加到 dst 中,注意是添加,而不是替换
//startWithMoveTo: 起始点是否使用 moveTo
boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)

getSegment 用于截取整个 Path 中的某个片段,通过参数 startD 和 stopD 来控制截取的长度,并将截取后的 Path 保存到参数 dst 中。最后一个参数 startWithMoveTo 表示起始点是否使用 moveTo 将路径的新起始点移到结果 Path 的起始点,通常设置为 true ,以保证每次截取的 Path 都是正常完整的,通常和 dst 一起使用,因为 dst 中保存的 Path 是被不断添加的,而不是每次被覆盖的;如果设置为 false ,则新增的片段会从上一次 Path 终点开始计算,这样可以保证截取的 Path 片段是连续的。

注意:

  • 如果 startD ,stopD 数值不在取值范围内,或者 startD == stopD ,那么就会返回 false ,并且 dst 不会有 Path 数据。
  • 开启硬件加速后,绘图会出现问题,因此,在使用 getSegment 是需要 在构造函数中调用 setLayerType(LAYER_TYPE_SOFTWARE,null) 函数来禁用硬件加速

getSegment 举例:

/**

  • 3. getSegment
    */
    mPath.addCircle(500f,500f,200f,Path.Direction.CCW)
    mPathMeasure.setPath(mPath,false)//不被闭合
    val segment = mPathMeasure.getSegment(50f, 500f, mTempPath, true)
    println(“是否截取成功:$segment”)
    canvas.drawPath(mTempPath,mPathPaint)

效果:

注意:

如果 startWithMoveTo 为 true,则被截取出来的 path 片段保持原状;如果 startWithMoveTo 为 false ,则会将截取出来的 Path 片段的起始点移动到 dst 的最后一个点,以保证 dst 路径的连续性。

实现一个实时截取的动画:

代码实现:

  1. 定义一个值动画

val valueAnimator = ValueAnimator.ofFloat(0f, 1f)
valueAnimator.addUpdateListener {
animation -> stopValues = animation.animatedValue as Float
invalidate()
}
valueAnimator.repeatCount = ValueAnimator.INFINITE
valueAnimator.setDuration(1500)
valueAnimator.start()

  1. 实时截取绘制

mPath.addCircle(500f,500f,200f,Path.Direction.CCW)
mPathMeasure.setPath(mPath,false)//不被闭合
mTempPath.rewind()
stop = mPathMeasure.length * stopValues
val start = (stop - (0.5 - Math.abs(stopValues - 0.5)) * mPathMeasure.length).toFloat()
val segment = mPathMeasure.getSegment(start, stop, mTempPath, true)
println(“总长度: m P a t h M e a s u r e . l e n g t h 是否截取成功 : {mPathMeasure.length} 是否截取成功: mPathMeasure.length是否截取成功:segment + start: s t a r t s t o p : start stop: startstop:stop”)
canvas.drawPath(mTempPath,mPathPaint)

getPosTan

这个方法是用于得到路径上某一长度的位置以及该位置的正切值

//distance:距离 Path 起点的长度,取值范围: 0 <= distance <= getLength
//pos:该点的坐标值 , 当前点在画布上的位置,有两个数值,分别为x,y坐标。
//tan:该点的正切值, 当前点在曲线上的方向,使用 Math.atan2(tan[1], tan[0]) 获取到正切角的弧度值。
boolean getPosTan (float distance, float[] pos, float[] tan)

下面以一个 demo 来讲解 getPosTan 具体使用,先来看一个效果图:

感觉是不是很炫,那么我们是怎么实现的呢?先来看一下核心代码,如下:

override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
//清楚 path 数据
mTempPath.rewind()
//绘制一个模拟公路
addLineToPath()
//测量 path,闭合
mPathMeasure!!.setPath(mTempPath, true)
//动态变化的值
mCurValues += 0.002f
if (mCurValues >= 1) mCurValues = 0f
//拿到当前点上的 正弦值坐标
mPathMeasure!!.getPosTan(mPathMeasure!!.length * mCurValues, pos, tan)
//通过正弦值拿到当前角度
val y = tan!![1].toDouble()
val x = tan!![0].toDouble()
var degrees = (Math.atan2(y, x) * 180f / Math.PI).toFloat()
println(“角度:$degrees”)
mMatrix!!.reset()
//拿到 bitmap 需要旋转的角度,之后将矩阵旋转
mMatrix!!.postRotate(degrees, mBitmap!!.width / 2.toFloat(), mBitmap!!.height / 2.toFloat())
//拿到 path 上的 pos 点随着点移动
mMatrix!!.postTranslate(pos!![0] - mBitmap!!.getWidth() / 2, pos!![1] - mBitmap!!.getHeight() / 2)
//绘制Bitmap和path
canvas!!.drawPath(mTempPath, mTempPaint)
canvas!!.drawBitmap(mBitmap!!, mMatrix!!, mTempPaint)

//重绘
postInvalidate()
}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

题外话

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多程序员朋友无法获得正确的资料得到学习提升,故此将并将重要的Android进阶资料包括自定义view、性能优化、MVC与MVP与MVVM三大框架的区别、NDK技术、阿里面试题精编汇总、常见源码分析等学习资料免费分享出来。
Android学习PDF+学习视频+面试文档+知识点笔记

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

需要的朋友,可以点赞关注+转发”前往免费领取!

自定义view、性能优化、MVC与MVP与MVVM三大框架的区别、NDK技术、阿里面试题精编汇总、常见源码分析等学习资料免费分享出来。
Android学习PDF+学习视频+面试文档+知识点笔记

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-fIHlKStz-1710773333204)]

需要的朋友,可以点赞关注+转发”前往免费领取!

希望我能够用我的力量帮助更多迷茫、困惑的朋友们,帮助大家在IT道路上学习和发展~

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: element-ui和vant-ui是两个不同的UI框架,它们的区别主要在以下几个方面: 1. 设计风格:element-ui的设计风格更加简洁、大气,适合企业级应用;vant-ui的设计风格更加轻盈、时尚,适合移动端应用。 2. 组件数量:element-ui的组件数量较多,包括表单、布局、导航、数据展示等多个方面;vant-ui的组件数量相对较少,主要集中在移动端的常用组件上。 3. 使用场景:element-ui适用于PC端的后台管理系统、企业级应用等;vant-ui适用于移动端的H5页面、小程序等。 总的来说,element-ui和vant-ui都是优秀的UI框架,选择哪一个要根据具体的项目需求和使用场景来决定。 ### 回答2: element-ui和vant-ui都是基于Vue框架的UI组件库,它们的共性在于提供了一系列常用的UI组件,为开发者提供了快速开发高质量Web应用的解决方案。由于二者都具有类似的作用,因此,这使得许多开发者困惑于在它们之间做出选择。 首先,element-ui是一个由饿了么前端团队开发的UI组件库,它包括了许多常用的UI组件如Button、Input、Select、Table等组件,这些组件都是组合在一起的,使得整个库看起来美观、简洁、易用。同时,element-ui也提供了丰富的主题定制功能,可以灵活地为网站或应用程序提供个性化界面。 相对于element-ui,vant-ui则倾向于提供更轻量、更加灵活的UI组件方案。vant-ui 提供的组件较少,但这些组件都设计得十分精简、轻快,能够快速响应用户操作。并且vant-ui支持按需加载,并有一个非常简单易懂的文档手册。 在UI组件库的功能性方面,element-ui更偏重于提供更丰富的UI组件组合、出色的主题美化和模板系统,它尤其适用于提供一些较为复杂的应用界面。而vant-ui更偏向于为主流应用场景提供快捷、便利、高效的解决方案。 总之,两个UI库各有所长,具体使用哪一个要根据具体应用场景、需求选择。 如果需要更加美观,复杂,大型的应用程序,element-ui会是一个更好的选择;而如果要开发更加轻便、快速、高效的应用,vant-ui也是不错的选择。 ### 回答3: Element-UI和Vant-UI都是比较成熟的UI组件库,用于构建各种Web应用。虽然它们都提供了类似的基本UI组件(比如按钮、表格、表单等),但是它们也有很多不同点。 1. 设计风格 Element-UI的设计风格比较扁平化,颜色使用比较鲜艳,真实感较强。它的设计着重于使页面的视觉效果更加直观、简洁、易于用户使用。 Vant-UI的设计风格较为简洁自然,是一种比较纯粹、未加工的设计风格。它的设计更加注重在产品美感和用户体验上。Vant-UI的颜色及元素的拼接让整个产品看起来自然,简洁美观。 2. 支持的组件 虽然Element-UI和Vant-UI都提供了大量的组件,但是它们的支持组件还是有一些区别的。 比如,Element-UI提供了比较成熟的富文本编辑器、时间轴、树形控件等组件;而Vant-UI则比较注重于移动端的UI组件,比如支持拖拽排序的宫格、下拉刷新、上拉加载等常见的控件。Element-UI从PC端出发,适配了大屏幕的设计,而Vant-UI从移动端出发,更注重于小屏幕的设计。 3. 性能 Element-UI和Vant-UI的性能也有所不同。在加载大量数据的情况下,Element-UI比Vant-UI缓存更好。但是在移动端,Vant-UI的性能比较卓越且稳定,体验非常流畅,而Element-UI的性能在移动端相对较差。 4. 社区支持 从社区支持来看,Element-UI提供的文档比Vant-UI更加完整。不仅提供了组件的API文档,还针对不同场景、不同组件提供了详细的示例代码,使开发人员可以更快速地上手使用组件。 Vant-UI虽然相对较新,但是更受年轻开发者的欢迎,由于Vant-UI比较注重移动端开发,所以社区用户更多的是移动端开发者。相比之下,Element-UI在PC端开发领域有更多的开发者。 综上所述,Element-UI和Vant-UI各有优缺点,开发人员可以根据自己的实际需求选择适合自己的UI组件库。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值