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/

相关推荐
阿巴斯甜14 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker15 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952716 小时前
Andorid Google 登录接入文档
android
黄林晴17 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android