安卓渐变的背景框实现

安卓渐变的背景框实现

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

多线程案例——阻塞队列

目录 一、阻塞队列 1. 生产者消费者模型 (1)解耦合 (2)“削峰填谷” 2. 标准库中的阻塞队列 3. 自己实现一个阻塞队列(代码) 4. 自己实现生产者消费者模型(代码) 一、阻塞队列…

【Pytorch】 理解张量Tensor

本文参加新星计划人工智能(Pytorch)赛道:https://bbs.csdn.net/topics/613989052 这是目录张量Tensor是什么?张量的创建为什么要用张量Tensor呢?总结张量Tensor是什么? 在深度学习中,我们经常会遇到一个概念&#xff…

更改Hive元数据发生的生产事故

今天同事想在hive里用中文做为分区字段。如果用中文做分区字段的话,就需要更改Hive元 数据库。结果发生了生产事故。导致无法删除表和删除分区。记一下。 修改hive元数据库的编码方式为utf后可以支持中文,执行以下语句: alter table PARTITI…

Vue初入,了解Vue的发展与优缺点

作者简介:一名计算机萌新、前来进行学习VUE,让我们一起进步吧。 座右铭:低头赶路,敬事如仪 个人主页:我叫于豆豆吖的主页 前言 从本章开始进行Vue前端的学习,了解Vue的发展,以及背后的故事。 一.vue介…

ASEMI代理瑞萨TW9992AT-NA1-GE汽车芯片

编辑-Z TW9992AT-NA1-GE是一款低功耗NTSC/PAL模拟视频解码器,专为汽车应用而设计。它支持单端、差分和伪差分复合视频输入。集成了对电池短路和对地短路检测,先进的图像增强功能,如可编程的自动对比度调整(ACA)和MIPI…

【Linux】网络编程套接字(下)

🎇Linux: 博客主页:一起去看日落吗分享博主的在Linux中学习到的知识和遇到的问题博主的能力有限,出现错误希望大家不吝赐教分享给大家一句我很喜欢的话: 看似不起波澜的日复一日,一定会在某一天让你看见坚持…

ASEMI代理MIMXRT1064CVJ5B原装现货NXP车规级MIMXRT1064CVJ5B

编辑:ll ASEMI代理MIMXRT1064CVJ5B原装现货NXP车规级MIMXRT1064CVJ5B 型号:MIMXRT1064CVJ5B 品牌:NXP /恩智浦 封装:LFGBA-196 批号:2023 安装类型:表面贴装型 引脚数量:196 类型&#…

【Hadoop-yarn-01】大白话讲讲资源调度器YARN,原来这么好理解

YARN作为Hadoop集群的御用调度器,在整个集群的资源管理上立下了汗马功劳。今天我们用大白话聊聊YARN存在意义。 有了机器就有了资源,有了资源就有了调度。举2个很鲜活的场景: 在单台机器上,你开了3个程序,分别是A、B…

Redis知识点汇总

前言 梳理知识 说一下项目中的Redis的应用场景 首先知道Redis的5大value类型: string,list,hash, set ,zset 2.基本上是缓存 3.为的是服务无状态, 4.无锁化 Redis是单线程还是多线程 1.无论什么版本,工作线程就一个 2.6.x高版本出现IO多线程

三天吃透操作系统面试八股文

本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~ Github地址:https://github.com/…

基于python的超市历年数据可视化分析

人生苦短 我用python Python其他实用资料:点击此处跳转文末名片获取 数据可视化分析目录人生苦短 我用python一、数据描述1、数据概览二、数据预处理0、导入包和数据1、列名重命名2、提取数据中时间,方便后续分析绘图三、数据可视化1、美国各个地区销售额的分布&…

进阶C语言——指针(二)【题目练习】

文章目录1.指针和数组概念的理解2.指针和数组笔试题解析一维数组字符数组二维数组1.指针和数组概念的理解 指针和数组 数组:能够存放一组相同类型的元素,数组的大小取决于数组的元素个数和元素类型指针:也是地址或指针变量,大小是…

Spring Cloud -- GateWay

为什么需要网关在微服务架构中,一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去调用。这样的话会产生很多问题,例…

重构·改善既有代码的设计.04之重构手法(下)完结

1. 前言 本文是代码重构系列的最后一篇啦。前面三篇《重构改善既有代码的设计.01之入门基础》、《重构改善既有代码的设计.02之代码的“坏味道”》、《重构改善既有代码的设计.03之重构手法(上)》介绍了基础入门,代码异味,还有部…

【Java】你真的懂封装吗?一文读懂封装-----建议收藏

博主简介:努力学习的预备程序媛一枚~博主主页: 是瑶瑶子啦所属专栏: Java岛冒险记【从小白到大佬之路】 前言 write in the front: 如何理解封装? 试想:我们使用微波炉的时候,只用设置好时间,按下“开始”…

[C++]反向迭代器

目录 前言: 1 对反向迭代器的构造思想 2 实现反向迭代器 3 完整代码 前言: 本篇文章主要介绍了STL容器当中的反向迭代器,可能有朋友会说:“反向迭代器有什么好学的?不一样还是迭代器吗,我正向能写出来&…

【js逆向】hook大全

▒ 目录 ▒🛫 导读需求1️⃣ 普通函数2️⃣ 对象方法(Class.prototype)3️⃣ 对象属性(Object.defineProperty)4️⃣ Proxy5️⃣ 批量hook示例🛬 文章小结📖 参考资料🛫 导读 需求 …

【面试题系列】K8S常见面试题

目录 序言 问题 1. 简单说一下k8s集群内外网络如何互通的吧 2.描述一下pod的创建过程 3. 描述一下k8s pod的终止过程 4.Kubernetes 中的自动伸缩有哪些方式? 5.Kubernetes 中的故障检测有哪些方式? 6.Kubernetes 中的资源调度有哪些方式&#xff…

如何优雅的用POI导入Excel文件

在企业级项目开发中,要经常涉及excel文件和程序之间导入导出的业务要求,那么今天来讲一讲excel文件导入的实现。java实现对excel的操作有很多种方式,例如EasyExcel等,今天我们使用的是POI技术实现excel文件的导入。POI技术简介1.P…

全连接神经网络

目录 1.全连接神经网络简介 2.MLP分类模型 2.1 数据准备与探索 2.2 搭建网络并可视化 2.3 使用未预处理的数据训练模型 2.4 使用预处理后的数据进行模型训练 3. MLP回归模型 3.1 数据准备 3.2 搭建回归预测网络 1.全连接神经网络简介 全连接神经网络(Multi-Layer Percep…