Compose 自定义 - 绘制 Draw

一、概念

  • 所有的绘制操作都是通过调整像素大小来执行的。若要确保项目在不同的设备密度和屏幕尺寸上都能采用一致的尺寸,请务必使用 .toPx() 对 dp 进行转换或者采用小数尺寸。 

二、Modifier 修饰符绘制

官方页面

在修饰的可组合项之上或之下绘制。

.drawWithContent

fun Modifier.drawWithContent(
    onDraw: ContentDrawScope.() -> Unit
)

在 Lambda 中调用 drawContent() 就是绘制所修饰的内容,由此控制先后顺序,后绘制的会显示在上面。

.drawBehind

fun Modifier.drawBehind(
    onDraw: DrawScope.() -> Unit
)

修饰的内容会显示在 Lambda 内容之上(底层是先绘制 Lambda 内容再绘制所修饰的内容,后绘制的会显示在上面)。

.drawWithCache

fun Modifier.drawWithCache(
    onBuildDrawCache: CacheDrawScope.() -> DrawResult
)

当绘制复杂效果时,不希望因为重组而重新创建 Lambda 中用于绘制的实例如 Bush、Path 等,这可能会产生内存抖动。在 Lambada 中调用 onDrawWithContent()、onDrawBehind() 就类似于上面两个修饰符的功能。

 

@Composable
fun Demo() {Row(modifier = Modifier.size(150.dp),horizontalArrangement = Arrangement.Center,verticalAlignment = Alignment.CenterVertically) {Image(painterResource(id = R.drawable.logo_wechat_square),contentDescription = null,modifier = Modifier.size(50.dp).drawWithContent {drawContent()drawRedDot()    //后绘制的会显示在上面})Image(painterResource(id = R.drawable.logo_wechat_square),contentDescription = null,modifier = Modifier.padding(start = 10.dp).size(50.dp).drawBehind {drawRedDot()})}
}fun DrawScope.drawRedDot() {drawCircle(color = Color.Red,radius = 18F,center = Offset(drawContext.size.width, 0f))
}

三、Canvas() 可组合项绘制

是一个可组合项。Compose 作为跨平台 UI 框架,所使用的 Canvas() 函数只是一个封装,最终还是调用具体平台即 Android 原生的 Canvas。

fun Canvas(

        modifier: Modifier,

        onDraw: DrawScope.() -> Unit

) = Spacer(modifier.drawBehind(onDraw))

发现该方法只是一个封装,真正绘制的是调用 drawBehind()。绘制内容是显示在 Spacer 下面的,由于 Spacer 是透明的,因此我们所绘制内容得以全部显示。

四、Brush

官方页面

用于绘制颜色(只指定一种颜色就是纯色)。

linearGradient

线性渐变

fun linearGradient(
        colors: List<Color>,        //渐变颜色
        start: Offset = Offset.Zero,        //开始的位置
        end: Offset = Offset.Infinite,        //结束的位置
        tileMode: TileMode = TileMode.Clamp        //重复模式
): Brush

水平渐变和垂直渐变底层就是调用的线性渐变。

horizontalGradient

水平方向渐变

fun horizontalGradient(
        colors: List<Color>,
        startX: Float = 0.0f,
        endX: Float = Float.POSITIVE_INFINITY,
        tileMode: TileMode = TileMode.Clamp
): Brush

verticalGradient

垂直方向渐变

fun verticalGradient(
        colors: List<Color>,
        startY: Float = 0.0f,
        endY: Float = Float.POSITIVE_INFINITY,
        tileMode: TileMode = TileMode.Clamp
): Brush

radialGradient

放射渐变

fun radialGradient(
        colors: List<Color>,
        center: Offset = Offset.Unspecified,        //中心位置
        radius: Float = Float.POSITIVE_INFINITY,        //半径
        tileMode: TileMode = TileMode.Clamp
): Brush

sweepGradient

扫描渐变

fun sweepGradient(
        colors: List<Color>,
        center: Offset = Offset.Unspecified
): Brush

4.2.1 使用 colorStop 更改颜色分布

自定义颜色在渐变中的显示方式,可以调整每种颜色的 colorStop 值,0 ~ 1 之间的小数。

val colorStops = arrayOf(0.0f to Color.Yellow,0.2f to Color.Red,1f to Color.Blue
)
Box(modifier = Modifier.requiredSize(200.dp).background(Brush.horizontalGradient(colorStops = colorStops))
)

 4.2.2 使用 TileMode 让图案重复显示

当未指定 Brush 的开始位置 start 和结束位置 end 时,默认会填满整个区域,只有在区域 > Brush 时 TileMode 才会在渐变中平铺。以下举例 HorizontalGradient 的效果。

TileMode.Repeated将区域剩余空间绘制为重复的顺序颜色。
TileMode.Mirror将区域剩余空间绘制为重复的反转颜色。
TileMode.Clamp将区域剩余空间绘制为结束颜色。
TileMode.Decal将区域剩余空间绘制为透明色。(仅适用于 API 31 及更高版本。可使用 TileMode.isSupported() 确定设备是否支持 TileMode。如果使用了不受支持的 TileMode,系统会应用默认的 TileMode.Clamp。)

 4.2.3 更改 Brush 大小

当知道绘制区域大小时(如在 DrawScope 中通过 size 获取)可以按照 TileMode 方式平铺,在不知道的情况下(如将 Brush 分配给文字)可以扩展 Shader 重写 createShader() 函数利用绘制区域大小 size 形参。对于 radialGradient 如果未指定中心位置 center 和半径radius,渐变将占据整个 DrawScope 但是是以宽高较小的那边为直径,此时自定义大小会获得更好的效果(发散到屏幕外边去)。

val listColors = listOf(Color.Yellow, Color.Red, Color.Blue)
val customBrush = remember {object : ShaderBrush() {override fun createShader(size: Size): Shader {return LinearGradientShader(colors = listColors,from = Offset.Zero,to = Offset(size.width / 4f, 0f),tileMode = TileMode.Mirror)}}
}
Box(modifier = Modifier.requiredSize(200.dp).background(customBrush)
)

4.2.4 使用图片作为 Brush

如需使用 ImageBitmap 作为 Brush,请以 ImageBitmap 的形式加载相应图片,然后创建 ImageShader Brush。可以应用于一下几种类型的绘制:背景、文字、画布。

val imageBrush =ShaderBrush(ImageShader(ImageBitmap.imageResource(id = R.drawable.dog)))//用于 background
Box(modifier = Modifier.requiredSize(200.dp).background(imageBrush)
)//用于 TextStyle
Text(text = "Hello Android!",style = TextStyle(brush = imageBrush,fontWeight = FontWeight.ExtraBold,fontSize = 36.sp)
)//用于 DrawScope#drawCircle()
Canvas(onDraw = {drawCircle(imageBrush)
}, modifier = Modifier.size(200.dp))

五、DrawScope

官方页面

在 DrawScope 中,可以访问到 drawContext 成员,它存储了以下信息:绘制尺寸size、封装的canvas、用来旋转缩放移动的transform,而通过 canvas.nativeCanvas 就能获取具体平台的实现,即可以调用 Android 原生的 Canvas 来实现更多需求。

绘制drawLine 画线
drawRect 画矩形
drawRoundRect 画圆角矩形
drawImage 绘制图片
drawCircle 画圆形
drawOval 画椭圆形
drawArc 画弧度跟扇形
drawPath 画路径
drawPoints 画点
行为inset 将DrawScope坐标空间平移
translate 平移坐标

rotate(旋转坐标)讲的是旋转了多少角度

rotateRad(旋转坐标)讲的是旋转了多少弧度

scale 缩放坐标
clipRect 裁剪矩形区域,绘制在裁剪好的矩形区域内。ClipOp.Difference从当前剪辑中减去提供的矩形。
clipPath 裁剪路径
drawIntoCanvas 直接提供底层画布
withTransform 组合转换

5.1 绘制

5.1.1 画线 drawLine()

fun drawLine(
        color: Color,
        start: Offset,
        end: Offset,
        strokeWidth: Float = Stroke.HairlineWidth,
        cap: StrokeCap = Stroke.DefaultCap,
        pathEffect: PathEffect? = null,
        /*FloatRange(from = 0.0, to = 1.0)*/
        alpha: Float = 1.0f,
        colorFilter: ColorFilter? = null,
        blendMode: BlendMode = DefaultBlendMode
    )

cap

线条两头的形状

StrokeCap.Butt 平的(默认)
StrokeCap.Square 也是平的但是长一截
StrokeCap.Round 圆的

pathEffect

线条效果

PathEffect.cornerPathEffect(radius: Float)

将线段之间的锐角替换为指定半径的圆角 radius是半径

PathEffect.dashPathEffect(intervals: FloatArray, phase: Float = 0f)

将形状绘制为具有给定间隔的一系列破折号。比如虚线 例如interval={20,5},第一个参数表示虚线的长度是20,5是虚线之间的间隔是5. phase 偏移

PathEffect.chainPathEffect(outer: PathEffect, inner: PathEffect)

创建一个PathEffect,将内部效果应用于路径,然后应用外部效果

PathEffect.stampedPathEffect(shape: Path, advance: Float, phase: Float,style: StampedPathEffectStyle)

用path表示的指定形状冲压绘制的路径.  shape要踩踏的路径,advance 每个冲压形状之间的前进间距, phase 在压印第一个形状之前要偏移的相位量, style如何在每个位置转换形状,因为它是冲压. style有三种取值 StampedPathEffectStyle.Translate 平移 ,StampedPathEffectStyle.Rotate 旋转,StampedPathEffectStyle.Morph 变形

 

5.2 行为

5.2.1 缩放 scale()

5.2.2 平移 translate()

5.2.3 旋转 rotate()

5.2.4 

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

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

相关文章

redis集群理论和搭建

目录 环境 一&#xff0c;安装和部署redis 1&#xff0c;安装 2&#xff0c;部署 ​编辑 3&#xff0c;允许非本机连接redis 二、主从模式 主从模式搭建&#xff1a; 三&#xff0c;哨兵模式 哨兵模式搭建 四&#xff0c;集群模式 架构细节: 心跳机制 集群模式搭建&#xff1a…

<多线程章节五>synchrosized的可重入特性

&#x1f490;专栏导读 本篇文章收录于多线程&#xff0c;也欢迎翻阅博主的其他文章&#xff0c;可能也会让你有不一样的收获&#x1f604; &#x1f341;JavaSE &#x1f33a;多线程 &#x1f342;数据结构 &#x1f490;synchrosized的可重入特性及死锁 可重入特性就是&…

力扣每日一题79:单词搜索

题目描述&#xff1a; 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格…

如何查找特定基因集合免疫基因集 炎症基因集

温故而知新&#xff0c;再次看下Msigdb数据库。它更新了很多内容。给我们提供了一个查询基因集的地方。 关注微信&#xff1a;生信小博士 比如纤维化基因集&#xff1a; 打开网址&#xff1a;https://www.gsea-msigdb.org/gsea/msigdb/index.jsp 2.点击search 3.比如我对纤维…

结构体数组经典运用---选票系统

结构体的引入 1、概念&#xff1a;结构体和其他类型基础数据类型一样&#xff0c;例如int类型&#xff0c;char类型&#xff0c;float类型等。整型数&#xff0c;浮点型数&#xff0c;字符串是分散的数据表示&#xff0c;有时候我们需要用很多类型的数据来表示一个整体&#x…

Parity 战略转型引热议,将如何推动波卡生态去中心化?

Polkadot 生态的区块链基础设施公司 Parity Technologies&#xff0c;最近宣布了一项重要的战略调整&#xff0c;即正在寻求在未来几个月内&#xff0c;将部分现有的市场职能转移给 Polkadot 生态系统内的多个去中心化团队&#xff0c;这将影响 Parity Technologies 未来几个月…

ffmpeg中examples编译报不兼容错误解决办法

ffmpeg中examples编译报不兼容错误解决办法 参考examples下的README可知&#xff0c;编译之前需要设置 PKG_CONFIG_PATH路径。 export PKG_CONFIG_PATH/home/user/work/ffmpeg/ffmpeg/_install_uclibc/lib/pkgconfig之后执行make出现如下错误&#xff1a; 基本都是由于库的版…

(el-Table)操作(不使用 ts):Element-plus 中 Table 多选框的样式等的调整

Ⅰ、Element-plus 提供的 Table 表格组件与想要目标情况的对比&#xff1a; 1、Element-plus 提供 Table 组件情况&#xff1a; 其一、Element-ui 自提供的 Table 代码情况为(示例的代码)&#xff1a; // Element-plus 自提供的代码&#xff1a; // 此时是使用了 ts 语言环境…

企业管理系统有哪些?

文章目录 企业管理系统一、ERP 企业资源计划&#xff08;Enterprise Resource Planning&#xff09;二、OMS 订单管理系统&#xff08;Order Management System&#xff09;三、WMS 仓库管理系统&#xff08;Warehouse Management System &#xff09;四、TMS 运输管理系统 (Tr…

第十三章---枚举类型与泛型

一&#xff0c;枚举类型 1.使用枚举类型设置常量 设置常量时&#xff0c;我们通常将常量放置在接口中&#xff0c;这样在程序中就可以直接使用。该常量稚因为在接口中定义常量时&#xff0c;该常量的修饰符为 final 与 static。 public interface Constants ( public static …

LVS集群-DR模式【部署高可用LVS-DR集群】

文章目录 2.2 实战&#xff1a;配置LVS-DR集群2.2.1 配置IP&#xff08;Director Server的部署配置&#xff09;2.2.2 生成ens33:1配置文件 &#xff08;Director Server的部署配置&#xff09;2.2.3 配置LVS-DR规则&#xff08;Director Server的部署配置&#xff09;2.2.4 两…

Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解

Docker 镜像读写层核心概念&#xff1a;rootfs、Union mount、image以及layser原理详解 文章目录 Docker 镜像读写层核心概念&#xff1a;rootfs、Union mount、image以及layser原理详解rootfsUnion mount为什么镜像层都是只读的去掉读写层的话会有什么问题 Docker镜像imageDoc…

AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细)

&#xff08;1&#xff09;acwing 4557. 最长上升子序列 4557. 最长上升子序列 - AcWing题库 给定一个长度为 N 的整数序列 a1,a2,…,aN。请你计算该序列的最长上升子序列的长度。上升子序列是指数值严格单调递增的子序列 输入格式 第一行包含整数 N第二行包含 N个整数 a1,a…

大语言模型(LLM)综述(四):如何适应预训练后的大语言模型

A Survey of Large Language Models 前言5. ADAPTATION OF LLMS5.1 指导调优5.1.1 格式化实例构建5.1.2 指导调优策略5.1.3 指导调优的效果5.1.4 指导调优的实证分析 5.2 对齐调优5.2.1 Alignment的背景和标准5.2.2 收集人类反馈5.2.3 根据人类反馈进行强化学习5.2.4 无需 RLHF…

一个比较特别的串口工具

这是08年写的一个 并网带电池逆变器 的通讯工具&#xff0c;和普通的串口调试器相比&#xff0c;多了一个【脚本】功能。能够通过【脚本】完成通讯测试。 PC发给DSP的01命令 01 10 1B 00 CF A3 00 00 90 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 电…

小程序开发——小程序的事件

1.事件对象 事件与事件对象概述 事件是一种用户行为&#xff0c;用户的点击、滑动等操作都可以成为事件。事件也是一种通信方式&#xff0c;能够完成视图层&#xff08;WXML页面文件&#xff09;与逻辑层&#xff08;JS逻辑文件&#xff09;之间的通信。 事件对象是指用户在点…

uniapp开发app,在ios真机上出现的css样式问题

比如下面的问题&#xff0c;在iphone 13上出现&#xff0c;在iphone xR上正常。 问题一&#xff1a;border:1rpx造成边框显示不全 在iphone13上border边框有一部分不显示&#xff1a; 在iphone xR上显示正常&#xff1a; 解决办法是&#xff1a; 将border边框设置中的1rpx改…

分享一款基于 AI 的 Chrome 插件

最近使用大模型比较多&#xff0c;公司虽然提供了免费的 ChatGPT 但是需要跳转特定页面才能访问&#xff0c;比较麻烦&#xff0c;于是就想到是否可以开发一款类似于有道词典一样的 Chrome 插件&#xff0c;可以在任意页面使用&#xff0c;虽然市面上也有类似的插件&#xff0c…

【ROS入门】机器人系统仿真——URDF集成Gazebo

文章结构 URDF与Gazebo基本集成流程创建功能包编写URDF或Xacro文件启动 Gazebo 并显示机器人模型 URDF集成Gazebo相关设置collisioninertial颜色设置 URDF集成Gazebo实操编写封装惯性矩阵算法的 xacro 文件复制相关 xacro 文件&#xff0c;并设置 collision inertial 以及 colo…

一文搞懂 MineCraft 服务器启动操作和常见问题 2023年10月

文章目录 前言1. 新建文件夹2. 创建 bat 文件3. 编辑 bat 文件4. 启动服务器5. 恭喜完成 文章持续更新中&#xff0c;如果你有问题可以通过 qq 1317699264 获取免费协助&#xff0c;解决的问题将会被更新到本文章中 前言 无论你是使用服务端整合包&#xff0c;还是从上一篇我的…