前言内容
以前通过自定义view可以绘制出各种效果,但这些效果多数还是存在于规则的图像,今天学习贝塞尔曲线,来绘制一些更特别的线条。
简单来说贝塞尔曲线通过控制点,可以绘制出各种路径。一般我们常用的二阶贝塞尔和三阶贝塞尔(对应的控制点数量不同)。这也是Android提供给我们的方法。
网上介绍的资料很多,可以全面了解下。下面我用二阶贝塞尔曲线绘制一个正弦曲线,然后在让曲线动起来,来模仿波浪吧。
内容部分
代码超级少,先从原理来简单分析下我们要做什么。
- 最重要的是计算绘制路线的点的集合,这里我们需要确定波开始的位置,和波峰波谷高度,还有就是波长
下面隐藏波长只是为了,移动的时候看起来是连续的。
注意:
一个连续的波需要四个点来完成。最后一个波说五个点,然后因为需要移动所以我们多加了一个波。所以公式是 4*n+5,这里的n是波峰,一个完整的波由一个波峰和一个波谷组成。
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
if (!isMeasured) {
isMeasured = true
viewWidth = measuredWidth
viewHeight = measuredHeight
//底部开始
mStartPoint = measuredHeight.toFloat() / 2
//波峰高度
mCrestHeight = viewHeight / 15f
//波峰长度
mCrestWidth = measuredWidth / 2
//隐藏一个波长
mLeftHide = -mCrestWidth.toFloat()
//几个波峰
val n = (viewWidth / mCrestWidth + 0.5).roundToInt()
for (i in 0..n * 4 + 4) {
//x坐标开始的位置为负的一个波长开始
var x = (i * mCrestWidth / 4).toFloat() - mCrestWidth
var y = 0f
when (i % 4) {
0, 2 -> y = mStartPoint
1 -> y = mStartPoint + mCrestHeight
3 -> y = mStartPoint - mCrestHeight
}
pointList.add(Point(x, y))
}
}
}
- 拿到运动的点的集合后就是绘制,这里需要调用quadTo方法传入两个点。然后是让绘制好曲线平移就可以看到波浪的效果了(很多动画效果都是通过改变view的坐标完成,特别是页面动画效果很多的时候)。
这里是绘制一个path,主要是顶部是一个波浪的形状。
注意:
- 每两个点就绘制出一个半个正弦图了。所以循环是两个点为一组开始的
- 然后绘制完成后要闭合找个path
- 发送消息不断移动x的数值,就可以动起来了
override fun onDraw(canvas: Canvas?) {
mRipplePath.reset()
mRipplePath.moveTo(pointList[0].x, pointList[0].y)
Log.d("RippleView", pointList.size.toString())
for (i in 0..(pointList.size - 3) step 2) {
Log.d("RippleView", i.toString())
mRipplePath.quadTo(pointList[i + 1].x, pointList[i + 1].y, pointList[i + 2].x, pointList[i + 2].y)
}
mRipplePath.lineTo(pointList.get(pointList.size - 1).getX(), viewHeight.toFloat())
mRipplePath.lineTo(mLeftHide, viewHeight.toFloat())
mRipplePath.close()
canvas!!.drawPath(mRipplePath, mPaint)
mHandler.sendEmptyMessageDelayed(1, 10)
}
总的来说就是上面两个步骤。
其实没什么内容,因为很简单。