亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android如何實現球型水波紋帶圓弧進度效果

發布時間:2021-06-28 09:19:58 來源:億速云 閱讀:184 作者:小新 欄目:移動開發

這篇文章主要為大家展示了“Android如何實現球型水波紋帶圓弧進度效果”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Android如何實現球型水波紋帶圓弧進度效果”這篇文章吧。

需求

如下,實現一個圓形水波紋,帶進度,兩層水波紋需要漸變顯示,且外圍有一個圓弧進度。

Android如何實現球型水波紋帶圓弧進度效果

思路

外圍圓弧進度:可以通過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, mHeight.toFloat(), 0f, mHeight * (1 - waveWaterLevelRatio),
       waveColors[1],
       null, Shader.TileMode.CLAMP
     )
     SweepGradient(
       centerX.toFloat(),
       centerY.toFloat(),
       circleColors[0],
       floatArrayOf(0f, value / 100f)
     )
    }
    in 47..54 -> {
     fWaveShader = LinearGradient(
       0f, mHeight.toFloat(), 0f, mHeight * (1 - waveWaterLevelRatio),
       waveColors[2],
       null, Shader.TileMode.CLAMP
     )
     sWaveShader = LinearGradient(
       0f, mHeight.toFloat(), 0f, mHeight * (1 - waveWaterLevelRatio),
       waveColors[3],
       null, Shader.TileMode.CLAMP
     )
     SweepGradient(
       centerX.toFloat(),
       centerY.toFloat(),
       circleColors[1],
       floatArrayOf(0f, value / 100f)
     )
    }
    else -> {
     fWaveShader = LinearGradient(
       0f, mHeight.toFloat(), 0f, mHeight * (1 - waveWaterLevelRatio),
       waveColors[4],
       null, Shader.TileMode.CLAMP
     )
     sWaveShader = LinearGradient(
       0f, mHeight.toFloat(), 0f, mHeight * (1 - waveWaterLevelRatio),
       waveColors[5],
       null, Shader.TileMode.CLAMP
     )
     SweepGradient(
       centerX.toFloat(),
       centerY.toFloat(),
       circleColors[2],
       floatArrayOf(0f, 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(),
     centerY.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(), centerY.toFloat(), innerRadius + ringWidth / 4, ringPaint)
 }
 private fun drawText(canvas: Canvas) {
  //繪制進度文字
  textPaint.isFakeBoldText = true
  textPaint.textSize = percentSize
  canvas.drawText(
    percent.toString(),
    centerX.toFloat(),
    centerY.toFloat() + textPaint.textSize / 2,
    textPaint
  )
  textPaint.isFakeBoldText = false
  textPaint.textSize = greedSize
  canvas.drawText(
    greedTip,
    centerX.toFloat(),
    centerY.toFloat() - textPaint.textSize * 2,
    textPaint
  )
 }
 private fun drawCircle(canvas: Canvas) {
  //繪制外圍進度圓圈
  canvas.drawArc(outerCircleRectf, 0f, 360f, false, outerNormalCirclePaint)
  canvas.drawArc(outerCircleRectf, 90f, percent * 3.6f, false, outerCirclePaint)
  canvas.drawCircle(
    centerX.toFloat(),
    centerY.toFloat(),
    innerRadius,
    bgCirclePaint
  )
 }
}

以上是“Android如何實現球型水波紋帶圓弧進度效果”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

崇仁县| 保亭| 龙井市| 泗阳县| 东台市| 德兴市| 舒兰市| 黄陵县| 新丰县| 兰溪市| 贵定县| 华阴市| 双城市| 驻马店市| 哈密市| 呼伦贝尔市| 威海市| 南漳县| 青海省| 客服| 奈曼旗| 开鲁县| 花莲市| 康保县| 正定县| 观塘区| 天津市| 柞水县| 从江县| 钟祥市| 左云县| 安新县| 麻城市| 古交市| 资中县| 阿拉善左旗| 前郭尔| 怀远县| 天等县| 隆化县| 丹阳市|