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/

相关推荐
消失的旧时光-194336 分钟前
Android 接入 Flutter(Add-to-App)最小闭环:10 分钟跑起第一个混合页面
android·flutter
城东米粉儿1 小时前
android StrictMode 笔记
android
Zender Han1 小时前
Flutter Android 启动页 & App 图标替换(不使用任何插件的完整实践)
android·flutter·ios
童无极1 小时前
Android 弹幕君APP开发实战01
android
赛恩斯1 小时前
kotlin 为什么可以在没有kotlin 环境的安卓系统上运行的
android·开发语言·kotlin
于山巅相见1 小时前
【3588】Android动态隐藏导航栏
android·导航栏·状态栏·android11
乡野码圣1 小时前
【RK3588 Android12】开发效率提升技巧
android·嵌入式硬件
eybk2 小时前
Beeware生成安卓apk取得系统tts语音朗读例子
android
zhangphil3 小时前
Android图像显示,CPU的Skia与GPU的Vulkan高性能渲染系统
android