安卓渐变的背景框实现

news2024/10/5 17:22:09

安卓渐变的背景框实现

  • 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;
   }


   @Override
   public 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);
   }

   @Override
   public void setAlpha(int alpha) {

   }

   @Override
   public void setColorFilter(@Nullable ColorFilter colorFilter) {

   }

   @Override
   public 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);
   }

   @Override
   public void setCornerRadii(@Nullable float[] radii) {
      this.mBorderRadii = radii;
      super.setCornerRadii(radii);
   }

   @Override
   public 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;
   }



   @Override
   public 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来实现,外层先绘制整体的背景色,内层比外层小一些像素,并盖在外层即可实现边框的效果。但这种实现方式有一种很大的缺陷,就是它不是真正意义上的边框,因为内层无法是透明的,如果是透明的,那么外层的颜色就露出来了,所以内层必须要用一个和整体控件一致的颜色来盖在上面,因此并不推荐这种方法。

好了,就写到这,祝大家天天开心。

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

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

相关文章

Python 爬虫进阶必备 | 某电影站视频采集加密参数逻辑分析

点击上方“咸鱼学Python”,选择“加为星标”第一时间关注Python技术干货!今日网站aHR0cHM6Ly96MS5tMTkwNy5jbi8/ang9JUU1JTkzJTg4JUU1JTg4JUE5JUMyJUI3JUU2JUIzJUEyJUU3JTg5JUI5JUU0JUI4JThFJUU1JUFGJTg2JUU1JUFFJUE0加密定位与分析分析的网站是一个电影…

强化学习分类与汇总介绍

1.强化学习(Reinforcement Learning, RL) 强化学习把学习看作试探评价过程,Agent选择一个动作用于环境,环境接受该动作后状态发生变化,同时产生一个强化信号(奖或惩)反馈给Agent,Agent根据强化信号和环境当…

记一次 .NET 某医疗住院系统 崩溃分析

一:背景 1. 讲故事 最近收到了两起程序崩溃的dump,查了下都是经典的 double free 造成的,蛮有意思,这里就抽一篇出来分享一下经验供后面的学习者避坑吧。 二:WinDbg 分析 1. 崩溃点在哪里 windbg 带了一个自动化分…

Ubuntu上搭建网站【建立数据隧道,降低开支】

上篇:Ubuntu搭建web站点并发布公网访问 目录 1.安装WordPress 2.创建WordPress数据库 3.安装相对URL插件 4.内网穿透将网站发布上线 1.命令行方式: 2.图形化操作方式 5.图书推荐 cpolar官网 1.安装WordPress 在前面的介绍中,我们为大…

Spring Cloud Alibaba全家桶(八)——Sentinel规则持久化

前言 本文小新为大家带来 Sentinel规则持久化 相关知识,具体内容包括,Sentinel规则推送三种模式介绍,包括:原始模式,拉模式,推模式,并对基于Nacos配置中心控制台实现推送进行详尽介绍~ 不积跬步…

【K8S系列】Pod详解

目录 序言 1 前言 2 为什么需要pod 3 什么是Pod? 3.1 Pod的组成 3.2 Pod的用途 3.3 Pod的生命周期 3.4 Pod的特点 4 Pod的使用 5 结论 序言 任何一件事情,只要坚持六个月以上,你都可以看到质的飞跃。 今天学习一下K8s-Pod相关内容&…

SQL Server的页面(pages )和盘区(extents)体系结构

pages 和 extents 体系结构一、背景二、页面和盘区2.1、页面2.2、大行支持2.3、行溢出注意事项2.4、盘区(extents)三、管理扩展数据块分配和可用空间3.1、管理扩展数据块分配3.2、跟踪可用空间四、管理对象使用的空间五、追踪修改后的盘区总结一、背景 …

Spring Cloud Alibaba全家桶(九)——分布式事务组件Seata

前言 本文小新为大家带来 分布式事务组件Seata 相关知识,具体内容包括分布式事务简介(包括:事务简介,本地事务,分布式事务典型场景,分布式事务理论基础,分布式事务解决方案)&#xf…

PyTorch 之 基于经典网络架构训练图像分类模型

文章目录一、 模块简单介绍1. 数据预处理部分2. 网络模块设置3. 网络模型保存与测试二、数据读取与预处理操作1. 制作数据源2. 读取标签对应的实际名字3. 展示数据三、模型构建与实现1. 加载 models 中提供的模型,并且直接用训练的好权重当做初始化参数2. 参考 pyto…

可视化CNN和特征图

卷积神经网络(cnn)是一种神经网络,通常用于图像分类、目标检测和其他计算机视觉任务。CNN的关键组件之一是特征图,它是通过对图像应用卷积滤波器生成的输入图像的表示。 理解卷积层 1、卷积操作 卷积的概念是CNN操作的核心。卷积是一种数学运算&#x…

当深度学习遇上Web开发:Spring和OpenAI如何实现图片生成?

文章目录一、简介1. 什么是Spring和OpenAI2. 生成图像的意义和应用场景二、相关技术介绍1. 深度学习模型2. GAN模型3. TensorFlow框架四、简单的Spring应用1. 搭建Spring项目2. 添加相关依赖3. 编写简单的控制器五、OpenAI API1. 介绍OpenAI API2. 搭建OpenAI API环境3. 配置AP…

Pytorch实现GCN(基于Message Passing消息传递机制实现)

文章目录前言一、导入相关库二、加载Cora数据集三、定义GCN网络3.1 定义GCN层3.1.1 消息传递阶段(message)3.1.2 消息聚合阶段(aggregate)3.1.3 节点更新阶段(update)3.1.4 定义传播过程(propag…

AI时代来临,如何把握住文档处理及数据分析的机遇

AI时代来临,如何把握住文档处理及数据分析的机遇前言一、生成式人工智能与元宇宙二、面向图像文档的复杂结构建模研究三、大型语言模型的关键技术和实现ChatGPT 介绍ChatGPT的三个关键技术四、ChatGPT与文档处理未来总结前言 在3月18日,由中国图象图形协…

【CVPR 2023】FasterNet论文详解

论文名称:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks 论文地址:https://arxiv.org/abs/2303.03667 作者发现由于效率低下的每秒浮点运算,每秒浮点运算的减少并不一定会导致类似水平的延迟减少。提出通过同时减少冗…

YOLOv2论文解读/总结

本章论文: YOLOv2论文(YOLO9000: Better, Faster, Stronger)(原文+解读/总结+翻译) 系列论文: YOLOv1论文解读/总结_yolo论文原文_耿鬼喝椰汁的博客-CSDN博客 前言 在YOLOv1推出一…

k8s 部署nginx 实现集群统一配置,自动更新nginx.conf配置文件 总结

k8s 部署nginx 实现集群统一配置,自动更新nginx.conf配置文件 总结 大纲 1 nginx镜像选择2 创建configmap保存nginx配置文件3 使用inotify监控配置文件变化4 Dockerfile创建5 调整镜像原地址使用阿里云6 创建deploy部署文件部署nginx7 测试使用nginx配置文件同步&…

ETL 与 ELT的关键区别

ETL 和 ELT 之间的主要区别在于数据转换发生的时间和地点 — 这些变化可能看起来很小,但会产生很大的影响! ETL 和 ELT 是数据团队引入、转换并最终向利益干系人公开数据的两种主要方式。它们是与现代云数据仓库和 ETL 工具的开发并行发展的流程。 在任…

来自清华的AdaSP:基于自适应稀疏成对损失的目标重识别

文章目录摘要1、简介2、相关工作3、方法3.1、稀疏成对损失3.2、最小难度的正样本挖掘4、实验4.1、与其他成对损失的比较4.2、消融研究5、结论摘要 论文链接:https://arxiv.org/abs/2303.18247 物体重识别(ReID)旨在从大型图库中找到与给定探针具有相同身份的实例。…

【分布式版本控制系统Git】| 国内代码托管中心-Gitee、自建代码托管平台-GitLab

目录 一:国内代码托管中心-码云 1. 码云创建远程库 2. IDEA 集成码云 3. 码云复制 GitHub 项目 二:自建代码托管平台-GitLab 1. GitLab 安装 2. IDEA 集成 GitLab 一:国内代码托管中心-码云 众所周知,GitHub 服务器在国外&…

Kaggle 赛题解析 | AMP 帕金森进展预测

文章目录一、前言二、比赛说明1. Evaluation2. Timeline3. Prize4. Code Requirements三、数据说明四、总结🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 竞赛题目:AMP-Parkinson’s Disease Progression Prediction 竞赛地址…