Android 自定义球型水波纹带圆弧进度效果(实例代码)

Android 自定义球型水波纹带圆弧进度效果(实例代码),第1张

概述Android 自定义球型水波纹带圆弧进度效果(实例代码) 需求 如下,实现一个圆形水波纹,带进度,两层水波纹需要渐变显示,且外围有一个圆弧进度. 思路 外围圆弧进度:可以通过canvas.drawArc()实现.由于圆弧需要实现渐变,可以通过给画笔设置shader(SweepGradient)渲染,为了保证圆弧起始的颜色值始终一致,需要动态调整shader的参数.具体参见 SweepGradient(centerX.toFloat(), centerY.toFloat(), circleColors[0], floatArrayOf(0f, value

需求

如下,实现一个圆形水波纹,带进度,两层水波纹需要渐变显示,且外围有一个圆弧进度。


思路

外围圆弧进度:可以通过canvas.drawArc()实现。由于圆弧需要实现渐变,可以通过给画笔设置shader(SweepGradIEnt)渲染,为了保证圆弧起始的颜色值始终一致,需要动态调整shader的参数。具体参见

SweepGradIEnt(centerX.tofloat(),centerY.tofloat(),circlecolors[0],floatArrayOf(0f,value / 100f))

第四个参数需要根据当前进度填写对应数据比例。不懂的同学可以自行百度查阅。

水波纹的实现:直接使用贝塞尔曲线Path.quadTo()实现,通过拉伸水平直线绘制波浪效果。可以通过控制拉伸点(waveAmplitude)距离水平线的高度,达到波浪高度的控制。至于波浪的移动,可以通过移动平移水平线的起始位置来实现,在使用动画循环即可,为了能够稳定的显示,绘制波浪时需要严格绘制整数倍周期的波浪。

园形的实现:绘制一个完整的圆形,然后通过Path.op()合并裁剪水波纹path。注意点就是AndroID6有个坑,使用该方法会有明显的抖动,为了解决该问题,我的做法是多画一层圆弧以掩盖此抖动。

生命周期的控制:为了减少某些时刻cpu的损耗,通过控制变量自定义lifeDelegate(基于kotlin的代理模式实现)来控制动画的开始暂停。由于笔者使用的框架基于MVVM,所以代码就没有使用attrs控制属性,这里就不做过多的修改了。

整体实现

class WaveVIEw(context: Context,attributeSet: AttributeSet? = null) : VIEw(context,attributeSet) { companion object {  const val RESUME = 0x1  const val Stop = 0x2  const val DESTROY = 0x3 } private var mWIDth = 0 //控件整体宽度 private var mHeight = 0 //控件整体高度 //控件中心位置,x,y坐标 private var centerX = 0 private var centerY = 0 private var outerRadius = 0//外圈圆环的半径 private var innerRadius = 250f//内部圆圈的半径 private var radiusdist = 50f//内外圆圈的半径差距 private var fWaveShader: linearGradIEnt? = null private var sWaveShader: linearGradIEnt? = null private var wavePath = Path() private var waveCirclePath = Path() private val waveNum = 2 //波浪的渐变颜色数组 private val wavecolors by lazy {  arraylistof(    //深红色    intArrayOf(color.parsecolor("#E8E6421A"),color.parsecolor("#E2E96827")),intArrayOf(color.parsecolor("#E8E6421A"),color.parsecolor("#E2F19A7F")),//橙色    intArrayOf(color.parsecolor("#E8FDA085"),color.parsecolor("#E2F6D365")),intArrayOf(color.parsecolor("#E8FDA085"),color.parsecolor("#E2F5E198")),//绿色    intArrayOf(color.parsecolor("#E8009EFD"),color.parsecolor("#E22AF598")),intArrayOf(color.parsecolor("#E8009EFD"),color.parsecolor("#E28EF0C6"))  ) } //外围圆环的渐变色 private val circlecolors by lazy {  arraylistof(    //深红色    intArrayOf(color.parsecolor("#FFF83600"),color.parsecolor("#FFF9D423")),//橙色    intArrayOf(color.parsecolor("#FFFDA085"),color.parsecolor("#FFF6D365")),//绿色    intArrayOf(color.parsecolor("#FF2AF598"),color.parsecolor("#FF009EFD"))  ) } private val wavePaint by lazy {  val paint = Paint()  paint.isAntiAlias = true  paint.strokeWIDth = 1f  paint } //波浪高度比例 private var waveWaterLevelRatio = 0f //波浪的振幅 private var waveAmplitude = 0f //波浪最大振幅高度 private var maxWaveAmplitude = 0f //外围圆圈的画笔 private val outerCirclePaint by lazy {  val paint = Paint()  paint.strokeWIDth = 20f  paint.strokeCap = Paint.Cap.ROUND  paint.style = Paint.Style.stroke  paint.isAntiAlias = true  paint } private val outernormalCirclePaint by lazy {  val paint = Paint()  paint.strokeWIDth = 20f  paint.color = color.parsecolor("#FFF2F3F3")  paint.style = Paint.Style.stroke  paint.isAntiAlias = true  paint } private val bgCirclePaint by lazy {  val paint = Paint()  paint.color = color.parsecolor("#FFF6FAFF")  paint.style = Paint.Style.FILL  paint.isAntiAlias = true  paint } private val textPaint by lazy {  val paint = Paint()  paint.style = Paint.Style.FILL  paint.textAlign = Paint.Align.CENTER  paint.isFakeBoldText = true  paint.isAntiAlias = true  paint } private val ringPaint by lazy {  val paint = Paint()  paint.style = Paint.Style.stroke  paint.color = color.WHITE  paint.isAntiAlias = true  paint } //外围圆圈所在的矩形 private val outerCircleRectf by lazy {  val rectF = RectF()  rectF.set(    centerX - outerRadius + outerCirclePaint.strokeWIDth,centerY - outerRadius + outerCirclePaint.strokeWIDth,centerX + outerRadius - outerCirclePaint.strokeWIDth,centerY + outerRadius - outerCirclePaint.strokeWIDth  )  rectF } //外围圆圈的颜色渐变器矩阵,用于从90度开启渐变,由于线条头部有个小圆圈会导致显示差异,因此从88度开始绘制 private val sweepMatrix by lazy {  val matrix = Matrix()  matrix.setRotate(88f,centerX.tofloat(),centerY.tofloat())  matrix } //进度 0-100 var percent = 0  set(value) {   fIEld = value   waveWaterLevelRatio = value / 100f   //y = -4 * x2 + 4x抛物线计算振幅,水波纹振幅规律更加真实   waveAmplitude =     (-4 * (waveWaterLevelRatio * waveWaterLevelRatio) + 4 * waveWaterLevelRatio) * maxWaveAmplitude//   waveAmplitude = if (value < 50) 2f * waveWaterLevelRatio * maxWaveAmplitude else (-2 * waveWaterLevelRatio + 2) * maxWaveAmplitude   val shader = when (value) {    in 0..46 -> {     fWaveShader = linearGradIEnt(       0f,mHeight.tofloat(),0f,mHeight * (1 - waveWaterLevelRatio),wavecolors[0],null,Shader.TileMode.CLAMP     )     sWaveShader = linearGradIEnt(       0f,wavecolors[1],Shader.TileMode.CLAMP     )     SweepGradIEnt(       centerX.tofloat(),value / 100f)     )    }    in 47..54 -> {     fWaveShader = linearGradIEnt(       0f,wavecolors[2],wavecolors[3],circlecolors[1],value / 100f)     )    }    else -> {     fWaveShader = linearGradIEnt(       0f,wavecolors[4],wavecolors[5],circlecolors[2],value / 100f)     )    }   }   shader.setLocalMatrix(sweepMatrix)   outerCirclePaint.shader = shader   invalIDate()  } private val greedTip = "Greed Index" //文本的字体大小 private var percentSize = 80f private var greedSize = 30f private var textcolor = color.BLACK //外围圆圈的画笔大小 private var outerstrokeWIDth = 10f private var fAnimatedValue = 0f private var sAnimatedValue = 0f //动画 private val fValueAnimator by lazy {  val valueAnimator = ValueAnimator()  valueAnimator.duration = 1500  valueAnimator.repeatCount = ValueAnimator.INFINITE  valueAnimator.interpolator = linearInterpolator()  valueAnimator.setfloatValues(0f,waveWIDth)  valueAnimator.addUpdateListener { animation ->   fAnimatedValue = animation.animatedValue as float   invalIDate()  }  valueAnimator } private val sValueAnimator by lazy {  val valueAnimator = ValueAnimator()  valueAnimator.duration = 2000  valueAnimator.repeatCount = ValueAnimator.INFINITE  valueAnimator.interpolator = linearInterpolator()  valueAnimator.setfloatValues(0f,waveWIDth)  valueAnimator.addUpdateListener { animation ->   sAnimatedValue = animation.animatedValue as float   invalIDate()  }  valueAnimator } //一小段完整波浪的宽度 private var waveWIDth = 0f var lifeDelegate by Delegates.observable(0) { _,old,new ->  when (new) {   RESUME -> onResume()   Stop -> onPause()   DESTROY -> onDestroy()  } } //设置中间进度文本的字体大小 fun setPercentSize(size: float) {  percentSize = size  invalIDate() } //设置中间提示文本的字体大小 fun setGreedSize(size: float) {  greedSize = size  invalIDate() } //设置文本颜色 fun setTextcolor(color: Int) {  textcolor = color  textPaint.color = textcolor  invalIDate() } //设置外围圆圈的宽度 fun setouterstrokeWIDth(wIDth: float) {  outerstrokeWIDth = wIDth  outerCirclePaint.strokeWIDth = outerstrokeWIDth  outernormalCirclePaint.strokeWIDth = outerstrokeWIDth  invalIDate() } //设置内圆半径 fun setInnerRadius(radius: float) {  innerRadius = radius  invalIDate() } overrIDe fun onSizeChanged(w: Int,h: Int,olDW: Int,oldh: Int) {  super.onSizeChanged(w,h,olDW,oldh)  mWIDth = wIDth - paddingStart - paddingEnd  mHeight = height - paddingtop - paddingBottom  centerX = mWIDth / 2  centerY = mHeight / 2  outerRadius = mWIDth.coerceAtMost(mHeight) / 2  radiusdist = outerRadius - innerRadius  waveWIDth = mWIDth * 1.8f  maxWaveAmplitude = mHeight * 0.15f } private fun onResume() {  if (fValueAnimator.isstarted) {   animatorResume()  } else {   fValueAnimator.start()   sValueAnimator.start()  } } private fun animatorResume() {  if (fValueAnimator.isPaused || !fValueAnimator.isRunning) {   fValueAnimator.resume()  }  if (sValueAnimator.isPaused || !sValueAnimator.isRunning) {   sValueAnimator.resume()  } } private fun onPause() {  if (fValueAnimator.isRunning) {   fValueAnimator.pause()  }  if (sValueAnimator.isRunning) {   sValueAnimator.pause()  } } private fun onDestroy() {  fValueAnimator.cancel()  sValueAnimator.cancel() } //当前窗口销毁时,回收动画资源 overrIDe fun onDetachedFromWindow() {  onDestroy()  super.onDetachedFromWindow() } overrIDe fun onDraw(canvas: Canvas) {  drawCircle(canvas)  drawWave(canvas)  drawText(canvas) } private fun drawWave(canvas: Canvas) {  //波浪当前高度  val level = (1 - waveWaterLevelRatio) * innerRadius * 2 + radiusdist  //绘制所有波浪  for (num in 0 until waveNum) {   //重置path   wavePath.reset()   waveCirclePath.reset()   var startX = if (num == 0) {//第一条波浪的起始位置    wavePath.moveto(-waveWIDth + fAnimatedValue,level)    -waveWIDth + fAnimatedValue   } else {//第二条波浪的起始位置    wavePath.moveto(-waveWIDth + sAnimatedValue,level)    -waveWIDth + sAnimatedValue   }   while (startX < mWIDth + waveWIDth) {    wavePath.quadTo(      startX + waveWIDth / 4,level + waveAmplitude,startX + waveWIDth / 2,level    )    wavePath.quadTo(      startX + waveWIDth / 4 * 3,level - waveAmplitude,startX + waveWIDth,level    )    startX += waveWIDth   }   wavePath.lineto(startX,mHeight.tofloat())   wavePath.lineto(0f,mHeight.tofloat())   wavePath.close()   waveCirclePath.addCircle(     centerX.tofloat(),innerRadius,Path.Direction.ccw   )   waveCirclePath.op(wavePath,Path.Op.INTERSECT)   //绘制波浪渐变色   wavePaint.shader = if (num == 0) {    sWaveShader   } else {    fWaveShader   }   canvas.drawPath(waveCirclePath,wavePaint)  }  //Fixme androID6设置Path.op存在明显抖动,因此多画一圈圆环  val ringWIDth = outerRadius - outerstrokeWIDth - innerRadius  ringPaint.strokeWIDth = ringWIDth / 2  canvas.drawCircle(centerX.tofloat(),innerRadius + ringWIDth / 4,ringPaint) } private fun drawText(canvas: Canvas) {  //绘制进度文字  textPaint.isFakeBoldText = true  textPaint.textSize = percentSize  canvas.drawText(    percent.toString(),centerY.tofloat() + textPaint.textSize / 2,textPaint  )  textPaint.isFakeBoldText = false  textPaint.textSize = greedSize  canvas.drawText(    greedTip,centerY.tofloat() - textPaint.textSize * 2,textPaint  ) } private fun drawCircle(canvas: Canvas) {  //绘制外围进度圆圈  canvas.drawArc(outerCircleRectf,360f,false,outernormalCirclePaint)  canvas.drawArc(outerCircleRectf,90f,percent * 3.6f,outerCirclePaint)  canvas.drawCircle(    centerX.tofloat(),bgCirclePaint  ) }}

总结

以上所述是小编给大家介绍的AndroID 自定义球型水波纹带圆弧进度效果(实例代码),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

总结

以上是内存溢出为你收集整理的Android 自定义球型水波纹带圆弧进度效果(实例代码)全部内容,希望文章能够帮你解决Android 自定义球型水波纹带圆弧进度效果(实例代码)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/web/1144251.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存