安卓渐变的背景框实现
安卓渐变的背景框实现
- 1.背景
- 实现方法
- 1.利用PorterDuffXfermode进行图层的混合,这是最推荐的方法,也是最有效的。
- 2.利用canvas裁剪实现,这个方法有个缺陷,就是圆角会出现毛边,也就是锯齿。
- 3.利用layer绘制边框
1.背景
万恶的设计小姐姐又来搞事情啦,你说好好的设计一个纯色的背景框框不好嘛,非要把一个框框弄成渐变的,如果不拿出放大镜估计没几个人能看出来它是渐变的。来,我让你看看是啥样


框子是从左到右渐变的,设计应该是做了一个底图,然后上面盖了一个白色圆角矩形。那么我们该怎么去实现它呢?
实现方法
下面介绍三种实现它的方法。先贴上源码地址,大家记得给个star
https://github.com/stramChen/AndroidGradientBorderDrawable.git
1.利用PorterDuffXfermode进行图层的混合,这是最推荐的方法,也是最有效的。
关于图形混合不明白的,推荐看下面的文章
https://blog.csdn.net/iispring/article/details/50472485
实现思路大致就是先在canvas上绘制一个渐变的圆角矩形,然后再利用clear混合模式在原矩形中间绘制一个较小的圆角矩形将中间的颜色擦除,即中间绘制的颜色和原颜色会混合成透明色,这样就能达到渐变框框的效果了,是不是很容易。废话不多说,直接上代码。
/*** @des: 渐变背景边框* @author: 569133338@qq.com* @date: 2023/2/23 16:19*/
public class BorderDrawable extends Drawable {public int mLeftBorderWidth = 0;public int mRightBorderWidth = 0;public int mTopBorderWidth = 0;public int mBottomBorderWidth = 0;public float mBorderRadius =0;public float[] mBorderRadii;Path mOuterPath = new Path();Path mInnerPath = new Path();private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private Shader mShader;private int mColor;private int[] mColors;private Integer mWidth;private Integer mHeight;private RectF mRectF;public BorderDrawable(int borderWidth) {this(borderWidth,borderWidth,borderWidth,borderWidth);}public void setCornerRadii(@Nullable float[] radii) {this.mBorderRadii = radii;}public void setCornerRadius(float radius) {this.mBorderRadius = radius;}public void setColor(int color){mColor = color;mPaint.setColor(mColor);}public void setColors(int[] colors){mColors = colors;}public BorderDrawable(int leftBorderWidth, int rightBorderWidth, int topBorderWidth, int bottomBorderWidth) {mLeftBorderWidth = leftBorderWidth;mRightBorderWidth = rightBorderWidth;mTopBorderWidth = topBorderWidth;mBottomBorderWidth = bottomBorderWidth;}@Overridepublic void draw(Canvas canvas) {int width = getBounds().width();int height = getBounds().height();if(mWidth == null || mHeight == null || mWidth != width || mHeight != height){mOuterPath.reset();mInnerPath.reset();if(Build.VERSION.SDK_INT >= 21){if(mBorderRadii != null){mOuterPath.addRoundRect(0,0,width,height,mBorderRadii, Path.Direction.CW);mInnerPath.addRoundRect(mLeftBorderWidth,mTopBorderWidth,width-mRightBorderWidth,height-mBottomBorderWidth,mBorderRadii, Path.Direction.CW);}else {mOuterPath.addRoundRect(0,0,width,height,mBorderRadius,mBorderRadius, Path.Direction.CW);mInnerPath.addRoundRect(mLeftBorderWidth,mTopBorderWidth,width-mRightBorderWidth,height-mBottomBorderWidth,mBorderRadius,mBorderRadius, Path.Direction.CW);}}else {if(mBorderRadii != null){mOuterPath.addRoundRect(new RectF(0,0,width,height),mBorderRadii, Path.Direction.CW);mInnerPath.addRoundRect(new RectF(mLeftBorderWidth,mTopBorderWidth,width-mRightBorderWidth,height-mBottomBorderWidth),mBorderRadii, Path.Direction.CW);}else {mOuterPath.addRoundRect(new RectF(0,0,width,height),mBorderRadius,mBorderRadius, Path.Direction.CW);mInnerPath.addRoundRect(new RectF(mLeftBorderWidth,mTopBorderWidth,width-mRightBorderWidth,height-mBottomBorderWidth),mBorderRadius,mBorderRadius, Path.Direction.CW);}}if(null != mColors){mShader = new LinearGradient(0, 0, width, 0,mColors, null, Shader.TileMode.REPEAT);mPaint.setShader(mShader);}mRectF = new RectF(0,0,width,height);mWidth = width;mHeight = height;}int layerId = canvas.saveLayer(mRectF, null, Canvas.ALL_SAVE_FLAG);canvas.drawPath(mOuterPath,mPaint);mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));canvas.drawPath(mInnerPath,mPaint);mPaint.setXfermode(null);canvas.restoreToCount(layerId);}@Overridepublic void setAlpha(int alpha) {}@Overridepublic void setColorFilter(@Nullable ColorFilter colorFilter) {}@Overridepublic int getOpacity() {return PixelFormat.UNKNOWN;}
}
使用方法也很简单
int[] colors = { Color.parseColor("#C084FF"), Color.parseColor("#8040FF") };//初始化并设置四个边框的宽度BorderDrawable borderDrawable = new BorderDrawable(5,5,5,30);//设置渐变色borderDrawable.setColors(colors);//设置圆角大小borderDrawable.setCornerRadius(20);//将设置好的,放到放到view里面即可view.setBackground(borderDrawable);
2.利用canvas裁剪实现,这个方法有个缺陷,就是圆角会出现毛边,也就是锯齿。
这个方法的思路基本上同上面一致,我们可以直接继承GradientDrawable来绘制外层的渐变背景,然后把颜色混合变成从原矩形中间进行画布的裁剪,把中间的画布给裁剪掉,这样不就只剩下边框了吗,哈哈哈。废话不多说,直接上代码啊。
/*** @des: 渐变背景边框* @author: 569133338@qq.com* @date: 2023/2/23 16:19*/
public class BorderDrawable2 extends GradientDrawable {public int mLeftBorderWidth = 0;public int mRightBorderWidth = 0;public int mTopBorderWidth = 0;public int mBottomBorderWidth = 0;public float mBorderRadius =0;public float[] mBorderRadii;Path mPath = new Path();public BorderDrawable2(int borderWidth) {this(borderWidth,borderWidth,borderWidth,borderWidth);}@Overridepublic void setCornerRadii(@Nullable float[] radii) {this.mBorderRadii = radii;super.setCornerRadii(radii);}@Overridepublic void setCornerRadius(float radius) {this.mBorderRadius = radius;super.setCornerRadius(radius);}public BorderDrawable2(int leftBorderWidth, int rightBorderWidth, int topBorderWidth, int bottomBorderWidth) {mLeftBorderWidth = leftBorderWidth;mRightBorderWidth = rightBorderWidth;mTopBorderWidth = topBorderWidth;mBottomBorderWidth = bottomBorderWidth;}@Overridepublic void draw(Canvas canvas) {int width = getBounds().width();int height = getBounds().height();if(Build.VERSION.SDK_INT >= 21){if(mBorderRadii != null){mPath.addRoundRect(mLeftBorderWidth,mTopBorderWidth,width-mRightBorderWidth,height-mBottomBorderWidth,mBorderRadii, Path.Direction.CW);}else {mPath.addRoundRect(mLeftBorderWidth,mTopBorderWidth,width-mRightBorderWidth,height-mBottomBorderWidth,mBorderRadius,mBorderRadius, Path.Direction.CW);}}else{if(mBorderRadii != null){mPath.addRoundRect(new RectF(mLeftBorderWidth,mTopBorderWidth,width-mRightBorderWidth,height-mBottomBorderWidth),mBorderRadii, Path.Direction.CW);}else {mPath.addRoundRect(new RectF(mLeftBorderWidth,mTopBorderWidth,width-mRightBorderWidth,height-mBottomBorderWidth),mBorderRadius,mBorderRadius, Path.Direction.CW);}}canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG|Paint.ANTI_ALIAS_FLAG));canvas.clipPath(mPath, Region.Op.DIFFERENCE);super.draw(canvas);}
}
使用方法也一如既往的简单
int[] colors = { Color.parseColor("#C084FF"), Color.parseColor("#8040FF") };//初始化并设置四个边框的宽度BorderDrawable2 borderDrawable2 = new BorderDrawable2(5,5,5,30);//设置渐变方向borderDrawable2.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT);//设置渐变色borderDrawable2.setColors(colors);//设置圆角大小borderDrawable2.setCornerRadius(20);//将设置好的,放到放到view里面即可view.setBackground(borderDrawable2);
3.利用layer绘制边框
这种方法网上有一大堆教程,这里就不再赘述了,基本思路就是利用layer的两层item来实现,外层先绘制整体的背景色,内层比外层小一些像素,并盖在外层即可实现边框的效果。但这种实现方式有一种很大的缺陷,就是它不是真正意义上的边框,因为内层无法是透明的,如果是透明的,那么外层的颜色就露出来了,所以内层必须要用一个和整体控件一致的颜色来盖在上面,因此并不推荐这种方法。
好了,就写到这,祝大家天天开心。
相关文章:
安卓渐变的背景框实现
安卓渐变的背景框实现1.背景实现方法1.利用PorterDuffXfermode进行图层的混合,这是最推荐的方法,也是最有效的。2.利用canvas裁剪实现,这个方法有个缺陷,就是圆角会出现毛边,也就是锯齿。3.利用layer绘制边框1.背景 万…...
【拳打蓝桥杯】算法前置课——时间复杂度与空间复杂度
文章目录前言为什么需要复杂度分析?大O复杂度表示法时间复杂度分析几种常见时间复杂度实例分析空间复杂度分析内容小结最后说一句🐱🐉作者简介:大家好,我是黑洞晓威,一名大二学生,希望和大家一…...
vite中动态引入图片,打包之后找不到图片地址?
一般来说项目中我们集中存放图片,然后希望在页面中直接引入! 更好的就是直接在模板中调用一个函数 然后传入图片的名字就可以显示出来 事实上确实可以办到,我们用到了一个 new URL import.meta.url这俩个东西 再src目录下 static 下创建一…...
Docker 常用命令大全
目录 一、Docker (一)Docker基础命令 (二)docker镜像命令 (三)docker容器命令 (四)docker运维命令 一、Docker 容器是一种虚拟化技术,容器是镜像实例…...
React项目规范:目录结构、根目录别名、CSS重置、路由、redux、二次封装axios
React项目(一)一、创建项目二、目录结构三、craco配置别名并安装less1.craco安装2.配置别名3.安装less四、CSS样式重置五、配置路由六、配置Redux1.创建大仓库2.创建小仓库(1)方式1:RTK(2)方式2…...
SystemVerilog 教程第一章:简介
SystemVerilog 教程像 Verilog 和 VHDL 之类的硬件描述语言 (HDL) 主要用于描述硬件行为,以便将其转换为由组合门电路和时序元件组成的数字块。为了验证 HDL 中的硬件描述正确无误,就需要具有更多功能特性的面向对象的编程语言 (OOP) 来支持复杂的测试过…...
【Java|基础篇】逻辑控制-顺序结构、分支结构和循环结构
文章目录顺序结构分支结构if单分支语句if else双分支语句if else if else多分支语句switch语句循环语句for循环while循环do while循环continuebreak总结顺序结构 顺序结构是指代码按照从上往下的顺序依次执行 分支结构 选择语句是条件成立时,才会执行的语句.共有三种.分为是if…...
【数据挖掘实战】——家用电器用户行为分析及事件识别(BP神经网络)
项目地址:Datamining_project: 数据挖掘实战项目代码 目录 一、背景和挖掘目标 1、问题背景 2、原始数据 3、挖掘目标 二、分析方法与过程 1、初步分析 2、总体流程 第一步:数据抽取 第二步:探索分析 第三步:数据的预处…...
Kmeans聚类算法-python
import random import pandas as pd import numpy as np import matplotlib.pyplot as plt # 计算欧拉距离 def calcDis(dataSet, centroids, k): clalist[] for data in dataSet: diff np.tile(data, (k, 1)) - centroids #相减 (np.tile(a,(2,1))就是把…...
Linux|奇怪的知识|locate命令---文件管理小工具
前言: Linux的命令是非常多的,有一些冷门的命令,虽然很少用,但可能会有意想不到的功能,例如,本文将要介绍的locate命令。 (平常很少会想到使用此命令,find命令使用的更多,偶然想起…...
Cadence Allegro 导出Function Pin Report报告详解
⏪《上一篇》 🏡《上级目录》 ⏩《下一篇》 目录 1,概述2,Function Pin Reportt作用3,Function Pin Report示例4,Function Pin Report导出方法4.1,方法14.2,方法2B站关注“硬小二”浏览更多演示视频 1,概述...
蓝桥杯2018年第九题-缩位求和
题目:在电子计算机普及以前,人们经常用一个粗略的方法来验算四则运算是否正确。比如:248 * 15 3720把乘数和被乘数分别逐位求和,如果是多位数再逐位求和,直到是1位数,得2 4 8 14 > 1 4 5;1 5 65…...
基于Yolv5s的口罩检测
1.Yolov5算法原理和网络结构 YOLOv5按照网络深度和网络宽度的大小,可以分为YO-LOv5s、YOLOv5m、YOLOv5l、YOLOv5x。本文使用YOLOv5s,它的网络结构最为小巧,同时图像推理速度最快达0.007s。YO-LOv5的网络结构主要由四部分组成,分别…...
Linux基本命令
Linux基本命令Linux的目录结构Linux命令入门目录切换相关命令(cd/pwd)相对路径、绝对路径和特殊路径符创建目录命令(mkdir)文件操作命令part1 (touch、cat、more)文件操作命令part2 (cp、mv、rm)查找命令 (which、find…...
云原生场景下的安全左移
本博客地址:https://security.blog.csdn.net/article/details/129430859 一、安全左移概述 安全左移需要考虑开发安全、软件供应链安全、镜像仓库、配置核查这四个部分。 首先是开发安全,安全团队需要关注代码漏洞,比如使用代码检查工具进…...
mysql面试经典问题
文章目录 1. 能说下myisam 和 innodb的区别吗?2. 说下mysql的索引有哪些吧,聚簇和非聚簇索引又是什么?3. 那你知道什么是覆盖索引和回表吗?4. 锁的类型有哪些呢5. 你能说下事务的基本特性和隔离级别吗?6. 那ACID靠什么保证的呢?7. 那你说说什么是幻读,什么是MVCC?幻读什…...
微信小程序|基于小程序+C#制作一个考试答题小程序
基于小程序+C#制作一个考试答题小程序打破传统线下考试答题的边界线问题,使考试不用再局限与某个统一的场所,只要有设备,哪里都能考试。 一、小程序...
【1605. 给定行和列的和求可行矩阵】
来源:力扣(LeetCode) 描述: 给你两个非负整数数组 rowSum 和 colSum ,其中 rowSum[i] 是二维矩阵中第 i 行元素的和, colSum[j] 是第 j 列元素的和。换言之你不知道矩阵里的每个元素,但是你知…...
Linux命令之nano命令
一、nano命令简介 nano是一个小型、免费、友好的编辑器,旨在取代非免费Pine包中的默认编辑器Pico。nano不仅复制了Pico的外观,还实现了Pico中一些缺失(或默认禁用)的功能,例如“搜索和替换”和“转到行号和列号”。nan…...
IT项目管理(作业1)
一.单选题(共12题,100.0分) 1.以下哪项是项目的一个实例?( ) A、改进现有的业务流程或程序B、为公司运营提供信息技术支持C、批量生产一种新近开发出来的家用电冰箱D、管理一个公司 我的答案:A 2.下列哪项不能成为项目结束的理由?( ) A…...
具身智能系统集成与计算效率优化路径探析
具身智能作为连接人工智能与物理世界的核心载体,通过融合感知、决策、执行等多模块实现自主交互,其系统集成的合理性与计算效率的高低,直接决定了智能体在复杂场景中的落地能力。当前,具身智能正从实验室走向产业化应用࿰…...
基于Altera Cyclone4 FPGA-EP4CE15F17C8核心板的硬件设计实战(原理图+PCB+AD09工程)
1. 从零开始搭建FPGA核心板硬件系统 第一次接触FPGA核心板设计时,我被密密麻麻的引脚和复杂的电源系统搞得头晕眼花。直到用AD09完整走完EP4CE15F17C8核心板的设计流程,才发现硬件开发就像搭积木——只要掌握模块化思维,菜鸟也能做出专业级设…...
OpenClaw多设备同步:GLM-4.7-Flash配置共享方案
OpenClaw多设备同步:GLM-4.7-Flash配置共享方案 1. 为什么需要多设备同步配置? 去年冬天,我在办公室和家里两台MacBook上分别部署了OpenClaw对接GLM-4.7-Flash模型。很快发现一个头疼的问题:每次在办公室调试好的技能参数&#…...
Go语言的context.WithCancel取消信号传播与资源清理在分布式系统中的协调
Go语言的context.WithCancel取消信号传播与资源清理在分布式系统中的协调 在分布式系统中,任务的取消与资源清理是确保系统稳定性和高效性的关键挑战。Go语言通过context包提供了优雅的解决方案,尤其是context.WithCancel机制,能够实现跨组件…...
RTX4090D显存优化:OpenClaw+Qwen3-32B-Chat批量处理千页PDF
RTX4090D显存优化:OpenClawQwen3-32B-Chat批量处理千页PDF 1. 为什么需要显存优化 当我第一次尝试用OpenClaw对接Qwen3-32B-Chat处理PDF文档时,遇到了一个棘手的问题——显存爆炸。当时只是处理一个200页的PDF,显存占用就飙到了22GB&#x…...
实测才敢推 AI论文工具推荐:2026最新测评与使用体验
2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…...
项目分享|VibeVoice:微软开源的前沿语音AI
引言 在语音合成(TTS)技术领域,长篇幅、多说话者、低延迟的自然语音生成一直是行业痛点。传统TTS模型往往受限于生成时长、说话者数量或实时响应速度,难以满足播客制作、智能对话等复杂场景需求。微软开源的VibeVoice框架彻底打破…...
OpenClaw硬件监控:nanobot定时报告系统资源使用情况
OpenClaw硬件监控:nanobot定时报告系统资源使用情况 1. 为什么需要自动化硬件监控 去年夏天,我的开发机因为内存泄漏问题突然宕机,导致一个重要的线上演示被迫推迟。当时我就意识到,手动检查系统资源的方式既不及时也不可靠。直…...
解锁网易云音乐解析工具:3个鲜为人知的实用技巧
解锁网易云音乐解析工具:3个鲜为人知的实用技巧 【免费下载链接】Netease_url 网易云无损解析 项目地址: https://gitcode.com/gh_mirrors/ne/Netease_url 网易云音乐解析工具作为一款专注于无损资源获取的开源项目,不仅能帮助用户轻松获取音乐文…...
String、StringBuilder、StringBuffer 的本质区别
作为 Java 开发者,String、StringBuilder、StringBuffer 这三个类几乎每天都在用。但面试官总爱问这道题,因为它背后藏着 JVM 内存模型、线程安全、性能优化等核心知识点。今天我们从本质出发,彻底把这三个类讲透。一、String 为什么不可变&a…...
