[自定义View]一个简单的渐变色ProgressBar

Android原生ProgressBar

原生ProgressBar样式比较固定,主要是圆形和线条;也可以通过style来设置样式。

style:

style 效果
@android:style/Widget.ProgressBar.Horizontal 水平进度条
@android:style/Widget.ProgressBar.Small 小型圆形进度条
@android:style/Widget.ProgressBar.Large 大型圆形进度条
@android:style/Widget.ProgressBar.Inverse 反色进度条
@android:style/Widget.ProgressBar.Small.Inverse 反色小型圆形进度条
@android:style/Widget.ProgressBar.Large.Inverse 反色大型圆形进度条
@android:style/Widget.Material** MD风格

原生的特点就是单调,实现基本的功能,使用简单样式不复杂;要满足我们期望的效果就只能自定义View了。

自定义ProgressBar

自定义View的实现方式有很多种,继承已有的View,如ImageView,ProgressBar等等;也可以直接继承自View,在onDraw中绘制需要的效果。 要实现的效果是一个横向圆角矩形进度条,内容为渐变色。 所以在设计时要考虑到可以定义的属性:渐变色、进度等。

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="progress">
        <attr name="progress" format="float" />
        <attr name="startColor" format="color" />
        <attr name="endColor" format="color" />
    </declare-styleable>
</resources>

View实现

这里直接继承子View,读取属性,在onDraw中绘制进度条。实现思路是通过定义Path来绘制裁切范围,确定绘制内容;再实现线性渐变LinearGradient来填充进度条。然后监听手势动作onTouchEvent,动态绘制长度。

同时开放公共方法,可以动态设置进度颜色,监听进度回调,根据需求实现即可。

kotlin 复制代码
package com.cs.app.view

/**
 *
 */
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import android.graphics.Shader
import android.util.AttributeSet
import android.view.View
import com.cs.app.R

class CustomProgressView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
    private val progressPaint = Paint()
    private val backgroundPaint = Paint()
    private var progress = 50f
    private var startColor = Color.parseColor("#4C87B7")
    private var endColor = Color.parseColor("#A3D5FE")
    private var x = 0f
    private var progressCallback: ProgressChange? = null

    init {
        // 初始化进度条画笔
        progressPaint.isAntiAlias = true
        progressPaint.style = Paint.Style.FILL

        // 初始化背景画笔
        backgroundPaint.isAntiAlias = true
        backgroundPaint.style = Paint.Style.FILL
        backgroundPaint.color = Color.GRAY

        if (attrs != null) {
            val typedArray = context.obtainStyledAttributes(attrs, R.styleable.progress)
            startColor = typedArray.getColor(R.styleable.progress_startColor, startColor)
            endColor = typedArray.getColor(R.styleable.progress_endColor, endColor)
            progress = typedArray.getFloat(R.styleable.progress_progress, progress)
            typedArray.recycle()
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        val width = width.toFloat()
        val height = height.toFloat()

        //绘制Path,限定Canvas边框
        val path = Path()
        path.addRoundRect(0f, 0f, width, height, height / 2, height / 2, Path.Direction.CW)
        canvas.clipPath(path)

        //绘制进度条
        val progressRect = RectF(0f, 0f, width * progress / 100f, height)
        val colors = intArrayOf(startColor, endColor)
        val shader = LinearGradient(0f, 0f, width * progress / 100f, height, colors, null, Shader.TileMode.CLAMP)
        progressPaint.shader = shader
        canvas.drawRect(progressRect, progressPaint)
    }

    override fun onTouchEvent(event: android.view.MotionEvent): Boolean {
        when (event.action) {
            android.view.MotionEvent.ACTION_DOWN -> {
                x = event.rawX
                
                //实现点击调整进度
                progress = (event.rawX - left) / width * 100
                progressCallback?.onProgressChange(progress)
                invalidate()
            }

            android.view.MotionEvent.ACTION_MOVE -> {
                //实现滑动调整进度
                progress = (event.rawX - left) / width * 100
                progress = if (progress < 0) 0f else if (progress > 100) 100f else progress
                progressCallback?.onProgressChange(progress)
                invalidate()
            }

            else -> {}
        }
        return true
    }

    fun setProgress(progress: Float) {
        this.progress = progress
        invalidate()
    }

    fun setOnProgressChangeListener(callback: ProgressChange) {
        progressCallback = callback
    }

    interface ProgressChange {
        fun onProgressChange(progress: Float)
    }
}

示例

Kotlin 复制代码
class CustomViewActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_custom_view)
        val progressTv: TextView = findViewById(R.id.progress_textview)
        val view: CustomProgressView = findViewById(R.id.progress)
        view.setProgress(50f)

        view.setOnProgressChangeListener(object : CustomProgressView.ProgressChange {
            override fun onProgressChange(progress: Float) {
                progressTv.text = "${progress.toInt()}%"
            }
        })
    }
}
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:background="#0E1D3C"
    android:layout_height="match_parent">

    <com.cs.app.view.CustomProgressView
        android:id="@+id/progress"
        android:layout_width="200dp"
        android:layout_height="45dp"
        app:endColor="#A3D5FE"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.274"
        app:progress="60"
        app:startColor="#4C87B7" />

    <TextView
        android:id="@+id/progress_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:textColor="#ffffff"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/progress" />
</androidx.constraintlayout.widget.ConstraintLayout>

效果如下:

相关推荐
小兵张健8 小时前
一场大概率没拿到 offer 的面试,让我更坚定去做喜欢的事
人工智能·面试·程序员
阿虎儿15 小时前
56条软件工程开发定律
程序员
程序员鱼皮17 小时前
Git WorkTree 是什么?凭什么能让 AI 编程效率翻倍?
git·ai·程序员·编程·ai编程
czkm17 小时前
AI有情绪吗?从AI夸我是写作领域大神说起
人工智能·程序员·ai编程
SimonKing21 小时前
AI编程工具装了一大堆,Skills 管理乱成粥?这个开源神器一招搞定!
java·后端·程序员
小兵张健1 天前
AI 带来的机遇,可能真的大于风险
程序员·openai·ai编程
WebInfra2 天前
Rsbuild 2.0 发布:即将支持 TanStack Start
前端·javascript·程序员
我就是马云飞2 天前
我废了!大厂10年的我面了20家公司,面试官让我回去等通知!
android·前端·程序员
橙某人2 天前
生产力悖论:AI Coding 的效率狂欢与秩序隐忧
程序员