Android——贝塞尔曲线的水波浪效果实现
16lz
2021-01-26
使用贝塞尔曲线实现的水波浪效果,在很多杀毒软件的进度条显示中都有应用:
这个效果呢以前在有一个项目中需要实现过,当时是使用的正弦曲线做的效果,不过后来发现贝塞尔曲线也可以做出相同的效果,并且代码更为优雅。
那么对于初学者来说呢,首先需要了解什么是贝塞尔曲线,网上有很多教程,这里我找到了比较容易看懂的博客:
贝塞尔曲线原理(实现图真漂亮)
我们常用的是二阶贝塞尔曲线,其推导公式为:
但是在Android中,Path类提供了qudto方法去绘制一段贝塞尔曲线,因此,只要知道3个点就可以绘制出一段贝塞尔曲线,只需要6个点就可以模拟出正弦波浪曲线。
实现思路:
1.首先大体上需要绘制两段横版S型曲线,然后使用动画效果不断左平移来实现波浪的滑动效果。
2.每一段S型曲线需要确定5个点的位置:
其中对应两段贝塞尔曲线,即P1-P3,P3-P5
3.绘制过程为首先new一个path,将path移动到P1点,然后计算P2,P3的坐标,通过path的rQuadTo(float dx1, float dy1, float dx2, float dy2)方法绘制出P1-P3的贝塞尔曲线,以此类推绘制P3-P5以及之后的另外两条贝塞尔曲线。
实现代码:
class WaveView : View { private var color: Int private var paint: Paint private var path: Path private var mWidth: Int = 0 private var mHeight: Int = 0 private var cX: Float = 0f private var cY: Float = 0f private var xOffset = 0f private var progress = 50 private val clipPath: Path private var left: Float = 0f private var top: Float = 0f private var right: Float = 0f private var bottom: Float = 0f private var xOffsetAnimator: ValueAnimator? = null fun startAnima() { if (xOffsetAnimator == null) { xOffsetAnimator = ValueAnimator.ofInt(0, width) xOffsetAnimator?.addUpdateListener { animation -> val value = animation.animatedValue as Int xOffset = (-value).toFloat() postInvalidate() } xOffsetAnimator?.interpolator = LinearInterpolator() xOffsetAnimator?.duration = 1500 xOffsetAnimator?.repeatCount = ValueAnimator.INFINITE } LogUtils.d("开始动画") xOffsetAnimator?.start() } constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { val array = context?.obtainStyledAttributes(attrs, R.styleable.WaveView) this.color = array!!.getColor(R.styleable.WaveView_WaveView_color, Color.BLUE) paint = Paint() path = Path() paint.color = this.color; clipPath = Path() array.recycle() } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) val dx = mWidth / 4f val dy = mHeight / 8f val yOffset = (100 - progress) / 100f * height val p1 = floatArrayOf(xOffset, yOffset) val p2 = floatArrayOf(dx, -dy) val p3 = floatArrayOf(2 * dx, 0f) val p4 = floatArrayOf(dx, dy) val p5 = floatArrayOf(2 * dx, 0f) val p6 = floatArrayOf(dx, -dy) val p7 = floatArrayOf(2 * dx, 0f) val p8 = floatArrayOf(dx, dy) val p9 = floatArrayOf(2 * dx, 0f) paint.style = Paint.Style.FILL path.reset() path.moveTo(p1[0], p1[1]) path.rQuadTo(p2[0], p2[1], p3[0], p3[1]) path.rQuadTo(p4[0], p4[1], p5[0], p5[1]) path.rQuadTo(p6[0], p6[1], p7[0], p7[1]) path.rQuadTo(p8[0], p8[1], p9[0], p9[1]) path.lineTo(width.toFloat(), height.toFloat()) path.lineTo(0f, height.toFloat()) path.close() clipPath.reset() left = 0f top = 0f right = mWidth.toFloat() bottom = height.toFloat() clipPath.addArc(left, top, right, bottom, 0f, 360f) // canvas!!.clipPath(clipPath) canvas!!.drawPath(path, paint) } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) mWidth = measuredWidth mHeight = measuredHeight cX = (mWidth / 2).toFloat() cY = (mHeight / 2).toFloat() }}
Github项目地址:
https://github.com/jiangzhengnan/UI
最近会把实现的UI效果都集中到一个库里面,求start~
更多相关文章
- android canvas常用的方法解析(一)
- 将JavaFX运行到Android上
- Android绘图机制(二)--2D绘图基础
- android 震动效果类
- Android(安卓)多个输入框的自动跳转
- 成佩涛编程之路——Android控件动画效果(二)
- Android(安卓)弹无虚发之第三弹:ActionBar 更换背景、颜色、文字,
- Android自动手绘,圆你儿时画家梦!
- Android模拟键盘输入功能的实现