Android 渐变色实现总结

项目中,为了实现好看的效果UI娘们会,设计出各式各样的渐变色效果,真是UI大手一挥,开发跑断腿(可能是我菜).这不又开始了 ,四种颜色,还根据位置动态位置实现倾斜角度渐变,好多页面要用.

人家切好图了....

不想往码子里放太多的图,所以还是肝一下这个渐变色吧

go-->go-->go

Android渐变色功能的底层实现依赖于图形渲染引擎和着色器(Shader)机制,核心原理是通过颜色插值算法坐标映射在指定区域内平滑过渡多种颜色。具体实现分为两大技术路径:

渐变色实现分类

  • Drawable资源系统(xml,GradientDrawable两种方式实现)
  • Shader(功能强大推荐手写)

1:Drawable资源系统(XML预定义+CPU解析)

通过XML定义静态渐变色,系统在运行时解析为GradientDrawable对象,然后实现各种渐变色

核心:

实质上是 将xml转为GradientDrawableGradientDrawable是Drawable的子类所以可以直接设置给控件做背景

所以Drawable资源系统实现渐变色可分为两类 xml静态资源实现渐变色和GradientDrawable对象实现渐变色

  • xml静态资源实现渐变色
  • GradientDrawable实现

注意:

1:XML 中最多只能设置3 种颜色(startColorcenterColorendColor) 2:角度限制:android:angle 必须是 45 的倍数,否则会自动取模(如设置 30° 实际会变为 30%45=30°)

1.1 xml静态资源实现渐变色

渐变色实现效果类型:

  • 线性渐变(LinearGradient)
  • 径向渐变(RadialGradient)
  • 扫描渐变(SweepGradient)

1.1.1 线性渐变(LinearGradient)

属性说明

  • 仅仅支持三种颜色
  • angle 渐变方向:0=左到右,45斜角90=上到下,,135对斜角,180=右到左,270=下到上
  • startColor 起始颜色
  • centerColor 中间颜色
  • endColor 结束颜色
  • useLevel 必须为false true时渐 变色会根据 level 值(范围 0-10000)动态调整显示效果
View设置
ini 复制代码
<View
    android:layout_margin="10dp"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:background="@drawable/gradient_linear"/>
    
资源 gradient_linear.xml
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
  <!--    仅仅支持三种颜色  -->
   <!-- angle 渐变方向:0=左到右,45斜角90=上到下,,135对斜角,180=右到左,270=下到上 -->
   <!-- startColor 起始颜色 -->
   <!-- centerColor 中间颜色 -->
   <!-- endColor   结束颜色 -->
   <!-- useLevel 必须为false  true时渐 变色会根据 level 值(范围 0-10000)动态调整显示效果-->
   <gradient
       android:angle="90"
       android:startColor="#FF4081"

       android:centerColor="@color/teal_200"
       android:endColor="#3F51B5"
       android:type="linear"
       android:useLevel="false" />
</shape>

1.1.2 径向渐变(RadialGradient)

属性说明:

  • 仅仅支持三种颜色
  • gradientRadius 渐变半径(必须设置)
  • centerX 中心点X坐标(0-1) -->
  • centerY 中心点Y坐标
  • startColor 起始颜色
  • centerColor 中间颜色
  • endColor 结束颜色
  • useLevel 必须为false true时渐 变色会根据 level 值(范围 0-10000)动态调整显示效果
View设置
ini 复制代码
<View
    android:layout_margin="10dp"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:background="@drawable/gradient_radial"/>
xml资源 gradient_radial.xml
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
   <!--    仅仅支持三种颜色  -->
    <!-- startColor 起始颜色 -->
    <!-- centerColor 中间颜色 -->
    <!-- endColor   结束颜色 -->
    <!-- useLevel 必须为false  true时渐 变色会根据 level 值(范围 0-10000)动态调整显示效果-->
    <!-- gradientRadius 渐变半径(必须设置) -->
    <!-- centerX 中心点X坐标(0-1) -->
    <!--  centerY 中心点Y坐标 -->
    <gradient
        android:type="radial"
        android:endColor="#3F51B5"
        android:centerColor="@color/teal_200"
        android:startColor="#FF4081"
        android:gradientRadius="70dp"
        android:centerX="0.5"
       android:centerY="0.5"
       android:useLevel="false"
        />
</shape>

1.1.3 扫描渐变(LinearGradient)

属性说明:

  • 仅仅支持三种颜色
  • centerX 中心点X坐标(0-1) -->
  • centerY 中心点Y坐标
  • startColor 起始颜色
  • centerColor 中间颜色
  • endColor 结束颜色
  • useLevel 必须为false true时渐 变色会根据 level 值(范围 0-10000)动态调整显示效果
View设置
ini 复制代码
<View
    android:layout_margin="10dp"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:background="@drawable/gradient_sweep"/>
xml资源 gradient_sweep.xml
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <!--    仅仅支持三种颜色  -->
    <!-- startColor 起始颜色 -->
    <!-- centerColor 中间颜色 -->
    <!-- endColor   结束颜色 -->
    <!-- useLevel 必须为false  true时渐 变色会根据 level 值(范围 0-10000)动态调整显示效果-->
    <!-- gradientRadius 渐变半径(必须设置) -->
    <!-- centerX 中心点X坐标(0-1) -->
    <!--  centerY 中心点Y坐标 -->
    <gradient
        android:type="sweep"
        android:endColor="#3F51B5"
        android:centerColor="@color/teal_200"
        android:startColor="#FF4081"
        android:centerX="0.5"
        android:centerY="0.5"
        android:useLevel="false"
        />
</shape>

1.2 GradientDrawable 代码实现渐变

scss 复制代码
val gradient = GradientDrawable(
    GradientDrawable.Orientation.BOTTOM_TOP,  // 渐变方向
    colors// 颜色数组
)
binding.view1.setBackgroundDrawable(gradient)


var gradient2 = GradientDrawable()
gradient2.setGradientType(GradientDrawable.RADIAL_GRADIENT)
gradient2.setColors(colors) // 从中心到边缘的颜色
gradient2.setGradientRadius(dp2px(70f).toFloat()) // 渐变半径(必须设置)
gradient2.setGradientCenter(0.5f ,0.5f )// 中心点 X 坐标(0-1)
binding.view2.setBackgroundDrawable(gradient2)

val gradient3 = GradientDrawable()
gradient3.setGradientType(GradientDrawable.SWEEP_GRADIENT)
gradient3.setColors(colors) // 颜色需首尾闭合
gradient3.setGradientCenter(0.5f ,0.5f )// 中心点 X 坐标(0-1)
binding.view3.setBackgroundDrawable(gradient3)

2.Shader渲染引擎(基于GPU的实时计算)

Shader是Android图形系统(android.graphics)的核心组件,负责定义像素填充规则。渐变色通过以下Shader子类实现:

  • 多颜色
  • 多位置
  • 多角度
  • LinearGradient(线性渐变)
  • RadialGradient(径向渐变)
  • SweepGradient(扫描渐变)

2.1 LinearGradient(线性渐变)

kotlin 复制代码
/**
 * 支持自定义线性渐变的View
 */
class LinearGradientView : View {
    // 1. 代码创建时调用
    constructor(context: Context?) : super(context)

    // 2. XML布局加载时必须调用(关键!)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)

    // 3. 可选:支持主题样式时添加
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    // 使用更合适的命名和初始化方式
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)

    // 使用val声明不可变数组,初始化颜色值
    private val colors = intArrayOf(
        Color.parseColor("#FF4081"),
        Color.parseColor("#FF03DAC5"),
        Color.parseColor("#3F51B5")
    )

    // 确保gradientLocations长度与colors一致
    private val gradientLocations = floatArrayOf(0f, 0.46f, 1f)

    // 缓存渐变对象,避免每次onDraw重新创建
    private var linearGradient: Shader? = null

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        // 当View尺寸变化时创建渐变对象
        if (w > 0 && h > 0) {
            linearGradient = LinearGradient(
                0f, 0f,
                w.toFloat(), h.toFloat(),
                colors,
                gradientLocations,
                Shader.TileMode.CLAMP
            )
            paint.shader = linearGradient
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 绘制矩形区域,应用渐变
        canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint)
    }
}

2.1 RadialGradient(径向渐变)

kotlin 复制代码
package com.wkq.tools.ui.view

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RadialGradient
import android.graphics.Shader
import android.util.AttributeSet
import android.view.View
import kotlin.math.min

/**
 * 支持径向渐变的自定义View
 */
class RadialGradientView : View {
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)

    // 使用不可变数组并修正颜色位置定义
    private val colors = intArrayOf(
        Color.parseColor("#FF4081"),
        Color.parseColor("#FF03DAC5"),
        Color.parseColor("#3F51B5")
    )

    // 确保颜色位置数组长度与颜色数组一致
    private val gradientLocations = floatArrayOf(0f, 0.46f, 1f)

    // 缓存渐变对象避免重复创建
    private var radialGradient: Shader? = null

    // 记录当前尺寸
    private var currentWidth = 0
    private var currentHeight = 0

    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context, attrs, defStyleAttr
    )

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        // 保存当前尺寸
        currentWidth = w
        currentHeight = h
        // 尺寸变化时重新创建渐变
        createRadialGradient()
    }

    private fun createRadialGradient() {
        if (currentWidth <= 0 || currentHeight <= 0) return

        val centerX = currentWidth / 2f
        val centerY = currentHeight / 2f
        val radius = min(centerX, centerY)

        radialGradient = RadialGradient(
            centerX, centerY,
            radius,
            colors,
            gradientLocations,
            Shader.TileMode.CLAMP
        )

        paint.shader = radialGradient
    }

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

        if (currentWidth <= 0 || currentHeight <= 0) return

        val centerX = currentWidth / 2f
        val centerY = currentHeight / 2f
        val radius = min(centerX, centerY)

        // 绘制圆形区域应用径向渐变
        canvas.drawCircle(centerX, centerY, radius, paint)
    }
}

2.3 SweepGradient(扫描渐变)

kotlin 复制代码
package com.wkq.tools.ui.view

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.SweepGradient
import android.util.AttributeSet
import android.view.View
import kotlin.math.min

/**
 * 支持扫描渐变的自定义View
 */
class SweepGradientView: View{
    // 1. 代码创建时调用
    constructor(context: Context?) : super(context)

    // 2. XML布局加载时必须调用(关键!)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)

    // 3. 可选:支持主题样式时添加
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)

    // 使用不可变数组存储颜色
    private val colors = intArrayOf(
        Color.parseColor("#FF4081"),
        Color.parseColor("#FF03DAC5"),
        Color.parseColor("#3F51B5")
    )

    // 确保颜色位置数组长度与颜色数组一致
    private val gradientLocations = floatArrayOf(0f, 0.46f, 1f)

    // 缓存渐变对象,避免每次onDraw重新创建
    private var sweepGradient: SweepGradient? = null

    // 记录当前尺寸
    private var currentWidth = 0
    private var currentHeight = 0

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        currentWidth = w
        currentHeight = h
        createSweepGradient()
    }

    private fun createSweepGradient() {
        if (currentWidth <= 0 || currentHeight <= 0) return

        val centerX = currentWidth / 2f
        val centerY = currentHeight / 2f

        sweepGradient = SweepGradient(
            centerX, centerY,
            colors,
            gradientLocations
        )

        paint.shader = sweepGradient
    }

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

        if (currentWidth <= 0 || currentHeight <= 0) return

        val centerX = currentWidth / 2f
        val centerY = currentHeight / 2f
        val radius = min(centerX, centerY)

        // 绘制圆形区域应用扫描渐变
        canvas.drawCircle(centerX, centerY, radius, paint)
    }
}

总结

Drawable资源系统 将XML静态资源转化为 GradientDrawable或者代码创建,可以直接设置给View控件作为背景

Shader方式实现渐变是给画笔设置Shader用于绘制的时候,适合在自定义View的时候.

相关推荐
Kapaseker5 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴5 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭15 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab16 小时前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe21 小时前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农1 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos
鹏程十八少1 天前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试
Kapaseker1 天前
一杯美式搞定 Kotlin 空安全
android·kotlin
三少爷的鞋1 天前
Android 协程时代,Handler 应该退休了吗?
android
火柴就是我2 天前
让我们实现一个更好看的内部阴影按钮
android·flutter