Android中如何实现自定义形状的WaterWave百分比填充效果
实现自定义形状的水波填充效果
核心思路
通过自定义View,结合Path裁剪和正弦曲线绘制水波,根据百分比控制水波的垂直偏移量,即可实现任意自定义形状的水波填充效果。
具体实现步骤
1. 搭建自定义View基础结构
创建继承自View的类,初始化画笔、路径等核心变量,并定义自定义形状的Path:
class CustomShapeWaveView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { // 自定义形状的路径(替换成你的目标形状) private val shapePath = Path() // 水波填充画笔 private val wavePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = Color.parseColor("#4A90E2") style = Paint.Style.FILL } // 形状轮廓画笔(可选,用于显示形状边框) private val shapeStrokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = Color.parseColor("#333333") style = Paint.Style.STROKE strokeWidth = 2f } // 水波水平偏移量,用于实现滚动动画 private var waveOffset = 0f // 当前填充百分比(0-100) private var fillPercent = 0f override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) // 重置自定义形状路径,这里替换成你的目标形状逻辑 resetTargetShapePath(w, h) } private fun resetTargetShapePath(width: Int, height: Int) { shapePath.reset() // 示例:绘制一个自定义不规则形状,你可以替换成自己的Path逻辑 val centerX = width / 2f val centerY = height / 2f shapePath.moveTo(centerX, centerY - height/3) shapePath.lineTo(centerX + width/3, centerY + height/4) shapePath.lineTo(centerX + width/5, centerY + height/2) shapePath.lineTo(centerX - width/5, centerY + height/2) shapePath.lineTo(centerX - width/3, centerY + height/4) shapePath.close() } }
2. 结合形状裁剪与水波绘制
通过画布裁剪限制水波绘制区域,再根据百分比计算水波的基准位置,绘制动态水波:
override fun onDraw(canvas: Canvas) { super.onDraw(canvas) // 绘制形状轮廓(可选) canvas.drawPath(shapePath, shapeStrokePaint) // 裁剪画布,仅在自定义形状区域内绘制内容 canvas.save() canvas.clipPath(shapePath) // 计算水波基准Y轴位置:0%在View底部,100%在View顶部 val baseWaveY = height - (fillPercent / 100f) * height // 绘制水波 drawDynamicWave(canvas, baseWaveY) canvas.restore() // 驱动水波滚动动画 waveOffset += 4f postInvalidateDelayed(30) } private fun drawDynamicWave(canvas: Canvas, baseY: Float) { val wavePath = Path() val waveWidth = width.toFloat() val waveHeight = 18f // 水波起伏高度,可按需调整 // 从View左侧外开始绘制正弦曲线 wavePath.moveTo(-waveWidth + waveOffset, baseY) for (x in -waveWidth.toInt()..width step (waveWidth / 2).toInt()) { val currentX = x + waveOffset // 绘制上半段曲线 wavePath.quadTo( currentX + waveWidth / 4, baseY - waveHeight, currentX + waveWidth / 2, baseY ) // 绘制下半段曲线 wavePath.quadTo( currentX + waveWidth * 3 / 4, baseY + waveHeight, currentX + waveWidth, baseY ) } // 闭合路径,将水波与View底部连接形成填充区域 wavePath.lineTo(width.toFloat(), height.toFloat()) wavePath.lineTo(0f, height.toFloat()) wavePath.close() canvas.drawPath(wavePath, wavePaint) }
3. 添加百分比控制接口
对外暴露方法,用于动态设置填充百分比:
fun setFillPercent(percent: Float) { // 限制百分比在0-100范围内 this.fillPercent = percent.coerceIn(0f, 100f) invalidate() }
关键细节说明
- 自定义形状替换:在
resetTargetShapePath()方法中,将示例的不规则形状Path替换成你的目标形状(可从SVG解析Path,或手动绘制路径)。 - 水波参数调整:修改
waveHeight调整水波起伏程度,修改waveOffset的增量调整滚动速度;若不需要动画,可移除postInvalidateDelayed(),仅在百分比变化时刷新视图。 - 性能优化:如果裁剪性能不佳,可改用
PorterDuffXfermode,将水波Path与形状Path通过SRC_IN模式混合,实现相同的遮罩效果。
内容的提问来源于stack exchange,提问作者Dr.KeyOk
相关产品推荐
相关产品推荐

