[自定义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 天前
学弟去字节面试,一小时被问了 50 题。。
计算机·面试·程序员·互联网·编程·开发·项目·简历
冰 河10 天前
《Nginx核心技术》第16章:实现Nginx的高可用负载均衡
运维·nginx·程序员·负载均衡·高可用
Android技术栈13 天前
鸿蒙(API 12 Beta6版)图形【 请求动画绘制帧率】方舟2D图形服务
程序员·harmonyos·鸿蒙·鸿蒙系统·openharmony·方舟2d图形·动画绘制
程序员鱼皮16 天前
大厂为啥都发苹果电脑?哪个系统是开发之王?
计算机·程序员·互联网·开发·编程经验
Android技术栈16 天前
鸿蒙(API 12 Beta3版)【通过字节数组生成码图】
程序员·移动开发·harmonyos·鸿蒙·鸿蒙系统·openharmony
Android技术栈19 天前
鸿蒙(API 12 Beta5版)【通过文本生成码图】
程序员·移动开发·harmonyos·鸿蒙·鸿蒙系统·openharmony·扫码
一丝晨光20 天前
你真的理解编程语言里的数据相等吗
java·开发语言·c++·面试·程序员·编程·相等
Android技术栈21 天前
鸿蒙(API 12 Beta3版)【使用ImageEffect编辑图片】图片开发指导
程序员·harmonyos·鸿蒙·鸿蒙系统·媒体·openharmony·图片
Android技术栈23 天前
鸿蒙(API 12 Beta3版)【使用智能PhotoPicker】Media Library Kit媒体文件管理服务
程序员·音视频·harmonyos·鸿蒙·鸿蒙系统·openharmony