Android 自定义View 绘制一条颜色渐变,粗细渐变的线

本文介绍如何在Android中自定义View,实现一条颜色和宽度渐变的线。通过LinearGradient设置颜色渐变,结合Path和Canvas绘制复杂形状,支持自定义起始和结束颜色及大小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义View 绘制一条颜色渐变,粗细渐变的线

效果图如下:
在这里插入图片描述
自定义View 代码

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.View


public class GradientWidthAndColorLine : View {
    private var mPaint : Paint ?= null
    private var mContext :Context ?= null
    private var mAttrs :AttributeSet? = null
    private var mStartSize  = 50f
    private var mEndSize = 10f
    private var mStartColor = 0
    private var mEndColor = 0
    constructor(context: Context?) : this(context, null)
    constructor(context: Context?, attrs: AttributeSet?) : this(
        context,
        attrs,
        0
    )

    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyleAttr: Int
    ) : super(context, attrs, defStyleAttr) {
        mContext = context
        mAttrs = attrs
        init()
    }


    @SuppressLint("Recycle")
    private fun init(){
       mAttrs?.let {
           val obtainStyledAttributes =
               mContext!!.obtainStyledAttributes(mAttrs, R.styleable.GradientWidthAndColorLine)
           mStartColor = obtainStyledAttributes.getColor(R.styleable.GradientWidthAndColorLine_gradient_start_color, 0)
           mEndColor = obtainStyledAttributes.getColor(R.styleable.GradientWidthAndColorLine_gradient_end_color,0)
           mStartSize =  obtainStyledAttributes.getDimension(R.styleable.GradientWidthAndColorLine_gradient_start_size, 50f)
           mEndSize = obtainStyledAttributes.getDimension(R.styleable.GradientWidthAndColorLine_gradient_end_size,10f)
           obtainStyledAttributes.recycle()
       }
        mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        mPaint?.let {
            it.style = Paint.Style.FILL
            it.color = mStartColor
        }
    }


    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        mPaint?.let {
            val linearGradient = LinearGradient(
                0f, 0f, 0f, measuredHeight.toFloat(), intArrayOf(
                    mStartColor,
                    mEndColor
                ), floatArrayOf(0.0f, 1.0f), Shader.TileMode.CLAMP
            )
            it.shader = linearGradient
            val path = Path()
            if(mStartSize  > mEndSize){

                Log.e("Glide","big")
                path.moveTo(0f,0f)
                path.lineTo( (mStartSize - mEndSize)/2 ,measuredHeight.toFloat())
                path.lineTo(((mStartSize - mEndSize)/2 + mEndSize) ,measuredHeight.toFloat())
                path.lineTo(mStartSize,0f)
                path.lineTo(0f,0f)
            }else{

                Log.e("Glide","small")
                path.moveTo(0f,measuredHeight.toFloat())
                path.lineTo(mEndSize,measuredHeight.toFloat())
                path.lineTo((mEndSize - mStartSize)/ 2  + mStartSize, 0f)
                path.lineTo((mEndSize - mStartSize)/ 2,0f)
                path.lineTo(0f,measuredHeight.toFloat())
            }

            path.close()
            canvas!!.drawPath(path,it)
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val executeMeasure = executeMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(executeMeasure[0],executeMeasure[1])
    }



    private fun executeMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) :ArrayList<Int>{
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)
        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)

        var width = 0

        width = if(widthMode == MeasureSpec.EXACTLY){
            // 测量模式为MatchParent 或者 赋予了具体的值

            if(mStartSize > mEndSize) {
                mStartSize.toInt()
            }else{
                mEndSize.toInt()
            }

        }else{
            // 测量模式为WrapContent
            if(mStartSize > mEndSize) {
                mStartSize.toInt()
            }else{
                mEndSize.toInt()
            }
        }
        return arrayListOf(width,heightSize)
    }


    fun setStartSize(startSize :Float,refresh :Boolean ?= false){
        mStartSize = startSize
        if(refresh!!){
            requestLayout()
            invalidate()
        }
    }


    fun setEndSize(endSize :Float,refresh :Boolean ?= false){
        mEndSize = endSize
        if(refresh!!){
            requestLayout()
            invalidate()
        }

    }

    fun setStartColor(startColor :Int,refresh :Boolean ?= false){
        mStartColor = startColor
        if(refresh!!){
            requestLayout()
            invalidate()
        }

    }



    fun setEndColor(endColor :Int,refresh :Boolean ?= false){
        mEndColor = endColor
        if(refresh!!){
            requestLayout()
            invalidate()
        }
    }
}

自定义属性

  <declare-styleable name="GradientWidthAndColorLine">
        <attr name="gradient_start_color" format="color"/>
        <attr name="gradient_end_color" format="color"/>
        <attr name="gradient_start_size" format="dimension"/>
        <attr name="gradient_end_size" format="dimension"/>
    </declare-styleable>

在布局中添加代码使用

  <com.coner.myapplication.GradientWidthAndColorLine
        android:id="@+id/line1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:gradient_end_color="@android:color/black"
        app:gradient_start_color="@android:color/holo_purple"
        app:gradient_start_size="5dp"
        app:gradient_end_size="2dp"
        android:layout_width="wrap_content"
        android:layout_height="300dp"/>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值