需求分析
需要做成一个如图的类似书签tab栏。
实现思路
直接用selector替换背景肯定可以,但是想试试许久没用的自定义控件。
继承view,onMeasure获得宽高,onDraw绘制背景,绘制选中颜色,绘制文字。看起来十分简单。
然而年轻的我还是太连清了。UI在左右两边分别加了一个圆角,这用路径就很难画了。
本来想用arcTo方法绘制
mPath.arcTo(ovalRectF, startAngle, sweepAngle) , ovalRectF为椭圆的矩形,startAngle 为开始角度,sweepAngle 为结束角度。
但通过尝试发现圆弧的曲率很难计算,画出来的圆弧角度很奇怪,打算使用贝塞尔曲线。
贝塞尔曲线扫盲
贝塞尔曲线不仅能画直线,也能画曲线。即便是更复杂的曲线,控制点的增加也只是线性的。这一特点使其不光在工业设计领域大展拳脚,就连数学基础不好的人也可以比较容易地掌握,比如大多数平面美术设计师们。
简单来说,贝塞尔曲线就是将任意一条曲线转化为准确的数学公式。 Bezier 曲线是用一系列点来控制曲线状态的。
贝塞尔曲线中有一些比较关键的名词,解释如下:
数据点:通常是指一条路径的起始点和终止点
-
控制点:控制点决定了一条路径的弯曲轨迹,根据控制点的个数,贝塞尔曲线被分为一阶贝塞尔曲线(0个控制点)、二阶贝塞尔曲线(1个控制点)、三阶贝塞尔曲线(2个控制点),以此类推。
Android中的贝塞尔曲线模拟
一般的开发者只考虑二阶贝塞尔曲线和三阶贝塞尔曲线,SDK也只提供了二阶和三阶的API调用。对于再高阶的贝塞尔曲线,通常可以将曲线拆分成多个低阶的贝塞尔曲线,也就是所谓的降阶操作。分别是下列方法
二阶 Path.quadTo()和rQuadTo() 前者基于绝对坐标,后者基于相对坐标。
三阶 Path.cubicTo()和rCubicTo() 前者基于绝对坐标,后者基于相对坐标。(参数比二阶多了一个控制点)
我只是想画一个润滑点的圆弧,所以使用Path.quadTo()方法来绘制圆弧
quadTo(float x1, float y1, float x2, float y2)
Add a quadratic bezier from the last point, approaching control point (x1,y1), and ending at (x2,y2).
把两条线反向延长,交于一点,这个点就是控制点。(别问我为啥,这个曲率就是刚刚好)
x2,y2是终点的坐标,默认是忽略起始坐标的(起始坐标就是你笔在的位置)
算控制点的过程比较难受,就省略啦。
然后在activity里面和fragment扯上关系就好了。
碰到的一些注意点
1. Invalidate方法实现界面刷新,但是Invalidate不能直接在子线程中调用
postInvalidate()可以在子线程中被调用
2. 不要在布局和绘图期间创建对象
3. 写自定义view的时候要注意Android的事件分发机制
dispatchTouchEvent(view的方法)---->onTouch(setontouchlistener)---->onTouchEvent(view的方法)----->onClick(setonclicklistener)
如果是通过重写onTouchEvent()来执行逻辑代码,那么给控件设置setonclicklistener就无效了。
具体的代码可以查看github仓库 点我跳转
参考文章
https://www.jianshu.com/p/55c721887568
https://juejin.im/post/57adbd9c79bc440058c9962d#comment