Android – 自定义多色渐变背景板
前言:
Android 自带的 xml 文件内 gradient 设置渐变最多只有三种颜色,使用方便但范围受限,不能很好满足各种需求;
本款多色渐变背景板应运而生:* 1. 支持圆角模式,矩形模式;* 2. 支持线性、扫描和环形渐变,线性渐变支持0-180角度设置;* 3. 支持多种颜色设置;(E.g: #ff0000 #00ff00 #0000ff)
使用:
//三种效果:
<LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_centerInParent="true"><com.nepalese.virgocomponent.view.VirgoGradientViewandroid: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.VirgoGradientViewandroid: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.VirgoGradientViewandroid: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 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
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);}@Overrideprotected 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;}@Overrideprotected 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;}//颜色种类不少于2public void setmColors(int[] mColors) {if (mColors.length < 2) {return;}this.mColors = mColors;}
}
渐变色网站:
https://webgradients.com/