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的时候.

相关推荐
xiangzhihong82 小时前
使用Universal Links与Android App Links实现网页无缝跳转至应用
android·ios
车载应用猿3 小时前
基于Android14的CarService 启动流程分析
android
雨白6 小时前
Jetpack系列(四):精通WorkManager,让后台任务不再失控
android·android jetpack
mmoyula8 小时前
【RK3568 驱动开发:实现一个最基础的网络设备】
android·linux·驱动开发
sam.li9 小时前
WebView安全实现(一)
android·安全·webview
移动开发者1号9 小时前
Kotlin协程超时控制:深入理解withTimeout与withTimeoutOrNull
android·kotlin
程序员JerrySUN10 小时前
RK3588 Android SDK 实战全解析 —— 架构、原理与开发关键点
android·架构
移动开发者1号10 小时前
Java Phaser:分阶段任务控制的终极武器
android·kotlin
哲科软件19 小时前
跨平台开发的抉择:Flutter vs 原生安卓(Kotlin)的优劣对比与选型建议
android·flutter·kotlin