Android -- [SelfView] 自定义多色渐变背景板

Android -- 自定义多色渐变背景板

前言:
Android 自带的 xml 文件内 gradient 设置渐变最多只有三种颜色,使用方便但范围受限,不能很好满足各种需求;
本款多色渐变背景板应运而生:
 * 1. 支持圆角模式,矩形模式;
 * 2. 支持线性、扫描和环形渐变,线性渐变支持0-180角度设置;
 * 3. 支持多种颜色设置;(E.g: #ff0000 #00ff00 #0000ff)
使用:
xml 复制代码
//三种效果:
<LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_centerInParent="true">

        <com.nepalese.virgocomponent.view.VirgoGradientView
            android:layout_width="160dp"
            android:layout_height="120dp"
            app:vgMode="mode_rect"
            app:vgRoundRadius="60dp"
            app:vgColors="#3f51b1 #5a55ae #7b5fac #8f6aae #a86aa4 #cc6b8e #f18271 #f3a469 #f7c978"
            app:vgGradientMode="gradient_linear"
            app:vgLinearAngle="15" />

        <com.nepalese.virgocomponent.view.VirgoGradientView
            android:layout_marginStart="20dp"
            android:layout_width="160dp"
            android:layout_height="120dp"
            app:vgMode="mode_round"
            app:vgRoundRadius="15dp"
            app:vgColors="#3f51b1 #5a55ae #7b5fac #8f6aae #a86aa4 #cc6b8e #f18271 #f3a469 #f7c978"
            app:vgGradientMode="gradient_linear"
            app:vgLinearAngle="30" />

        <com.nepalese.virgocomponent.view.VirgoGradientView
            android:layout_marginStart="20dp"
            android:layout_width="120dp"
            android:layout_height="120dp"
            app:vgMode="mode_round"
            app:vgRoundRadius="60dp"
            app:vgColors="#3f51b1 #5a55ae #7b5fac #8f6aae #a86aa4 #cc6b8e #f18271 #f3a469 #f7c978"
            app:vgGradientMode="gradient_linear"
            app:vgLinearAngle="45" />
    </LinearLayout>

码源:

1. attrs.xml
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
	<declare-styleable name="VirgoGradientView">
        <attr name="vgMode" format="integer">
            <enum name="mode_round" value="1"/>
            <enum name="mode_rect" value="2"/>
        </attr>
        <attr name="vgGradientMode" format="integer">
            <enum name="gradient_linear" value="1"/>
            <enum name="gradient_sweep" value="2"/>
            <enum name="gradient_radial" value="3"/>
        </attr>
        <attr name="vgLinearAngle" format="integer"/>
        <attr name="vgRoundRadius" format="dimension|reference"/>
        <attr name="vgColors" format="string"/>
    </declare-styleable>
</resources>
2. VirgoGradientView.java
java 复制代码
package com.nepalese.virgocomponent.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;

import com.nepalese.virgocomponent.R;

/**
 * @author nepalese on 2024/10/10 10:10
 * @usage 多色渐变调板:
 * 1. 支持圆角模式,矩形模式;
 * 2. 支持线性、扫描和环形渐变,线性渐变支持0-180角度设置;
 * 3. 支持多种颜色设置;(E.g: #ff0000 #00ff00 #0000ff)
 */
public class VirgoGradientView extends View {
    private static final String TAG = "VirgoGradientView";

    public static final int MODE_ROUND = 1;//圆角模式
    public static final int MODE_RECT = 2;//矩形模式(默认)

    public static final int GRADIENT_LINEAR = 1;//线性渐变
    public static final int GRADIENT_SWEEP = 2;//扫描渐变
    public static final int GRADIENT_RADIAL = 3;//环形渐变

    private Paint mPaint;//画笔
    private RectF mRectF;//画布矩形
    private Shader mShader;//渐变渲染

    private int mWidth, mHeight;//宽高
    private int mMode;//图形模式
    private int mGradientMode;//渐变模式
    private int mAngle;//线性渐变角度(从左->右:0-180)
    private int mRoundRadius;//圆角半径(仅圆角模式)
    private int[] mColors;//颜色组

    public VirgoGradientView(Context context) {
        this(context, null);
    }

    public VirgoGradientView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VirgoGradientView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    private void init(AttributeSet attrs) {
        String strColors;//颜色按顺序,以空格间开
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.VirgoGradientView);
        mMode = typedArray.getInt(R.styleable.VirgoGradientView_vgMode, MODE_RECT);
        mAngle = typedArray.getInt(R.styleable.VirgoGradientView_vgLinearAngle, 0);
        mGradientMode = typedArray.getInt(R.styleable.VirgoGradientView_vgGradientMode, GRADIENT_LINEAR);
        mRoundRadius = typedArray.getDimensionPixelSize(R.styleable.VirgoGradientView_vgRoundRadius, 20);
        strColors = typedArray.getString(R.styleable.VirgoGradientView_vgColors);
        typedArray.recycle();

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.FILL);

        //初始化默认颜色
        initColor(strColors);
    }

    private void initColor(String strColors) {
        if (TextUtils.isEmpty(strColors)) {
            strColors = "#69EACB #EACCF8 #6654F1";//默认
        }
        if (strColors.contains(" ")) {
            String[] colors = strColors.split(" ");
            mColors = new int[colors.length];
            for (int i = 0; i < colors.length; i++) {
                try {
                    mColors[i] = Color.parseColor(colors[i]);
                } catch (Exception e) {
                    mColors[i] = Color.WHITE;
                }
            }
        } else {
            //单色
            mColors = new int[1];
            try {
                mColors[0] = Color.parseColor(strColors);
            } catch (Exception e) {
                //格式异常
                Log.e(TAG, "格式异常!");
                mColors[0] = Color.WHITE;
            }
        }

//        //彩虹色
//        mColors = new int[7];
//        mColors[0] = Color.rgb(255,0,0);
//        mColors[1] = Color.rgb(255,165,0);
//        mColors[2] = Color.rgb(255,255,0);
//        mColors[3] = Color.rgb(0,255,0);
//        mColors[4] = Color.rgb(0,127,255);
//        mColors[5] = Color.rgb(0,0,255);
//        mColors[6] = Color.rgb(139,0,255);
    }

    private void setShader() {
        switch (mGradientMode) {
            case GRADIENT_LINEAR:
                //x0,y0,x1,y1是起始位置和渐变的结束位置
                //positions指定颜色数组的相对位置: [0...1], 如果传null,渐变就线性变化
                //角度正切值
                double tan = Math.tan(Math.PI * mAngle / 180);
                if (45 > mAngle && mAngle >= 0) {
                    //[0,45)
                    mShader = new LinearGradient(0, (float) ((mHeight - tan * mWidth) / 2), mWidth, (float) ((mHeight + tan * mWidth) / 2), mColors, null, Shader.TileMode.CLAMP);
                } else if (135 >= mAngle && mAngle >= 45) {
                    //[45,135]
                    if (mAngle == 90) {
                        mShader = new LinearGradient(mWidth / 2f, 0, mWidth / 2f, mHeight, mColors, null, Shader.TileMode.CLAMP);
                    } else {
                        mShader = new LinearGradient((float) ((mWidth - mHeight / tan) / 2), 0, (float) ((mWidth + mHeight / tan) / 2), mHeight, mColors, null, Shader.TileMode.CLAMP);
                    }
                } else if (180 >= mAngle && mAngle > 135) {
                    mShader = new LinearGradient(mWidth, (float) ((mHeight + tan * mWidth) / 2), 0, (float) ((mHeight - tan * mWidth) / 2), mColors, null, Shader.TileMode.CLAMP);
                } else {
                    //默认左 -> 右
                    mShader = new LinearGradient(0, 0, mWidth, 0, mColors, null, Shader.TileMode.CLAMP);
                }
                break;
            case GRADIENT_SWEEP:
                //cx,cy,圆的中心坐标
                mShader = new SweepGradient(mWidth / 2f, mHeight / 2f, mColors, null);
                break;
            case GRADIENT_RADIAL:
                //cx,cy,中心坐标
                int max = Math.max(mWidth, mHeight);
                mShader = new RadialGradient(mWidth / 2f, mHeight / 2f, max / 2f, mColors, null, Shader.TileMode.CLAMP);
                break;
        }

        mPaint.setShader(mShader);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //在measure之后, layout之前
        mRectF = new RectF(0, 0, w, h);
        mWidth = w;
        mHeight = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        setShader();

        if (mMode == MODE_RECT) {
            //矩形
            canvas.drawRect(mRectF, mPaint);
        } else {
            //圆角
            canvas.drawRoundRect(mRectF, mRoundRadius, mRoundRadius, mPaint);
        }
    }

    //api//
    public void setmMode(int mMode) {
        this.mMode = mMode;
    }

    public void setmGradientMode(int mGradientMode) {
        this.mGradientMode = mGradientMode;
    }

    public void setmAngle(int mAngle) {
        this.mAngle = mAngle % 180;
    }

    public void setmRoundRadius(int mRoundRadius) {
        this.mRoundRadius = mRoundRadius;
    }

    //颜色种类不少于2
    public void setmColors(int[] mColors) {
        if (mColors.length < 2) {
            return;
        }
        this.mColors = mColors;
    }
}

渐变色网站:

https://webgradients.com/

相关推荐
忘忧记4 小时前
Python MySQL SQLServer操作
android
万岳科技系统开发4 小时前
外卖系统开发实战:从架构设计到代码实现
android·小程序·开源
standxy5 小时前
通过轻易云平台实现聚水潭数据高效集成到MySQL的技术方案
android·数据库·mysql
he_wen_jian7 小时前
Android 项目引入gradle Connect timed out
android
哎呦没7 小时前
企业OA管理系统:Spring Boot技术实现与案例研究
android·spring boot·后端
李新_9 小时前
一文聊聊Flutter多业务混合工程实践
android·flutter
weixin_SAG12 小时前
7天掌握SQL - 第三天:MySQL实践与索引优化
android·sql·mysql
疯狂的皮卡14 小时前
【安卓脚本】Android工程中文硬编码抽取
android
菜鸟、小高15 小时前
从0开始学PHP面向对象内容之常用设计模式(适配器,桥接,装饰器)
android·设计模式·php
找藉口是失败者的习惯16 小时前
Jetpack Compose 生命周期介绍
android·ui