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

news2024/10/11 1:39:04

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

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

在这里插入图片描述

使用:
//三种效果:
<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 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);
    }

    @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/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2203801.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

同望OA tooneAssistantAttachement.jsp 任意文件读取漏洞复现

0x01 产品简介 同望OA,即同望科技打造的智企云协同管理系统,是一款高效的企业协同移动办公系统。秉承“互联网++企业管理”理念,定位于以移动互联办公为基础的企业协同管理软件平台。它旨在通过内置常用标准模块与专项管理模块应用,安全快速地打通管理与业务通道,实现管理…

微软最新 Office 办公软件2025下载 – Microsoft 365 正版优惠订阅

​ 以前 Office 365 是微软打造的「办公软件订阅」服务。订阅后&#xff0c;用户可以在多个平台使用Word、Excel、PowerPoint、OneDrive云存储网盘等正版办公应用。 微软希望这种订阅方式能够推广到更多的产品和用户&#xff0c;于是决定将 Office 365 升级为全新的「Microsoft…

【数据结构】6道经典链表面试题

目录 1.返回倒数第K个节点【链接】 ​代码实现 2.链表的回文结构【链接】 代码实现 3.相交链表【链接】 代码实现 4.判断链表中是否有环【链接】 代码实现 常见问题解析 5.寻找环的入口点【链接】 代码实现1 ​代码实现2 6.随机链表的复制【链接】 代码实现 1.…

51单片机的无线通信智能车库门【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块红外传感器光照传感器时钟模块步进电机蓝牙按键、LED、蜂鸣器等模块构成。适用于智能车库自动门、无线控制车库门等相似项目。 可实现功能: 1、LCD1602实时显示北京时间和自动/手动模式&#xff0c;以及验证是否成…

盘点2024年双十一最值得入手的好物,双十一购物清单宝藏好物推荐

随着2024年双十一购物节的脚步逐渐临近&#xff0c;消费者们正摩拳擦掌&#xff0c;准备迎接这场年度最大的购物狂欢。在这个特别的日子里&#xff0c;各大品牌纷纷推出前所未有的优惠活动&#xff0c;各种好物琳琅满目&#xff0c;让人眼花缭乱&#xff0c;为了帮助大家在这海…

机器学习、深度学习评价指标汇总:TP、TN、FP、FN、AP、mAP、IoU、mAP@3、Prec@10、 Acc@10

系列文章目录 文章目录 系列文章目录一、真正例&#xff08;True Positive&#xff09;、假正例&#xff08;False Positive&#xff09;、真负例&#xff08;True Negative&#xff09;和假负例&#xff08;False Negative&#xff09;是评估分类模型性能的重要概念。1. 定义2…

基于多种机器学习的酒店客户流失预测模型的研究与实现

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍实现过程 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 项目背景&#xff1a; 在当今竞争激烈的酒店行业中&#xff0c;预测和防止客户流…

什么是PCB和PCBA,他们的区别是什么?

相信很多人对于PCB电路板并不陌生&#xff0c;可能是日常生活中也能经常听到&#xff0c;但对PCBA或许就不太了解&#xff0c;甚至把和PCB混淆起来。那么PCB是什么&#xff1f;PCBA是如何演变出来的&#xff1f;PCB与PCBA的区别又是什么呢&#xff1f;方案商如何高效找到供应商…

Ubuntu 22.04.4 LTS更换下载源

方法1&#xff1a;使用图形界面更换下载源 1. 打开软件和更新应用 2. 在Ubuntu 软件标签中&#xff0c;点击“下载自”旁边的下拉菜单&#xff0c;选择“其他” 3. 点击“选择最佳服务器”来自动选择最快的服务器 4. 选择服务器 5. 确定并关闭窗口&#xff0c;系统会提示您重新…

应变计的校准方法和周期是怎样的?

应变计的校准方法和周期应变计是用于测量物体应变的关键设备&#xff0c;广泛应用于工程测试和科学研究领域。正确的校准方法和合理的校准周期对于确保应变计测量结果的准确性至关重要。校准方法应变计的方法通常涉及以下几个步骤&#xff1a; 零点校准&#xff1a;这是校准过程…

跨界的胜利:机器学习与神经网络的物理之光

近日&#xff0c;2024年诺贝尔物理学奖颁发给了机器学习与神经网络领域的研究者&#xff0c;这是历史上首次出现这样的情况。这项奖项原本只授予对自然现象和物质的物理学研究作出重大贡献的科学家&#xff0c;如今却将全球范围内对机器学习和神经网络的研究和开发作为了一种能…

Robust多模态模型的开发

本文所涉及所有资源均在 传知代码平台 可获取。 目录 Robust 多模态模型&#xff1a;寻找遗失的模态&#xff01; 一、研究背景 二、模型结构和代码 三、数据集介绍 六、性能展示 六、实现过程 七、运行过程 Robust 多模态模型&#xff1a;寻找遗失的模态&#xff01; 近年来&a…

MPLS LDP协议

文章目录 LDP标签分发协议工作原理LDP应用倒数第二跳弹出 LDP标签分发协议 基于FEC自动分配标签构建LSP用于建立动态LSPLDP报文头部结构信息类型 工作原理 LDP工作过程 发送Hello消息用于发现邻居&#xff1b;UDP发送LSR_1主动发起并建立TCP连接&#xff1b;TCP进行建立主动方发…

Node.js安装与配置 [详细步骤(实践操作)]

安装与配置 安装Node.js一、(1).下载&#xff08;可以直接在浏览器下的电脑&#xff09;一、(2).下载&#xff08;有些电脑不能在浏览器下载&#xff0c;比如&#xff1a;在浏览器下出来的是IDEA图标&#xff09;二、安装三、配置环境变量 验证是否安装成功修改模块下载位置一、…

十几天8.7万粉丝,柒奶奶疯狂老太太图文笔记,为什么这么火?项目拆解!利用这个软件一键生成图文,赚钱到手软!

每个行业一有变化&#xff0c;那肯定会带来不少新机会&#xff0c;AI 绘画也是这样。就说小某书账号“人间清醒柒奶奶”吧&#xff0c;在有 AI 绘画之前&#xff0c;柒奶奶的角色和动作都得靠人用手画&#xff0c;可麻烦了。但现在呢&#xff0c;在网站上输入几个词儿就能轻轻松…

大贤3D家谱-保存、删除与重建

保存&#xff1a;对于创建的节点、内容进行本地存储。 重建&#xff1a;清除没有保存的数据&#xff0c;重现保存过的历史节点。 删除&#xff1a;删除包括该节点的所有子节点信息。 灵活的使用模式​ 为了保证软件的持续健康发展&#xff0c;我们采用了试用付费的模式。用…

微同城源码系统帮你轻松制作本地生活服务平台 带完整的安装代码包以及搭建部署教程

系统概述 微同城源码系统是一款基于Web技术开发而成的开源项目&#xff0c;旨在为广大用户提供一个灵活、高效且易于管理的本地生活服务平台构建工具。该系统采用了流行的前后端分离架构设计模式&#xff0c;前端部分利用React框架实现动态交互界面&#xff1b;后端则采用Spri…

什么是好的性能测试报告?

一、性能测试报告编写技巧 在对结果进行分析并得出结论之后&#xff0c;性能测试工程师要把它们以文字报告的形式发送给相关人员。这就是性能测试报告。除了书面文字之外&#xff0c;可能的话&#xff0c;公司还会召集人员开专门的会议进行报告讲解和结果分析。所以&#xff0…

redis同步解决 缓存击穿+缓存穿透 原理代码实现

缓存穿透 就是一个根本不存在的数据 请求过来&#xff0c;然后 发现缓存没有&#xff0c;就打到数据库&#xff0c;然后 数据库也没有&#xff0c;就会给数据库造成很大的压力 &#xff0c; 解决方案 就是老生常谈的 返回null值&#xff0c;或者布隆过滤器 我们说 返回nul…

linux查看k8s的开机启动状态 systemctl is-enabled 查看开机启动状态

查看k8s的开机启动状态 在Kubernetes中&#xff0c;通常使用systemd来管理服务的启动。但是&#xff0c;Kubernetes节点上的服务可能不是由systemd直接管理&#xff0c;而是通过kubelet服务来管理。因此&#xff0c;检查Kubernetes节点的开机启动状态&#xff0c;你需要检查ku…