当前位置: 首页 > backend >正文

Compose笔记(二十四)--Canvas

        这一节主要了解一下Compose中Canvas,在Jetpack Compose中,Canvas是用于创建自定义绘图和动画的核心组件,它提供了强大的API来绘制各种图形、图像和效果。简单总给如下:

API
1.1 基本图形

// 绘制圆形
drawCircle(color = Color.Red, radius = 50f)// 绘制矩形
drawRect(color = Color.Blue, size = Size(100f, 150f))// 绘制圆角矩形
drawRoundRect(color = Color.Green,cornerRadius = CornerRadius(10f, 10f)
)// 绘制椭圆
drawOval(color = Color.Yellow, topLeft = Offset(50f, 50f))// 绘制线条
drawLine(color = Color.Black,start = Offset(0f, 0f),end = Offset(100f, 100f),strokeWidth = 5f
)

1.2 路径 (Path)

val path = Path().apply {moveTo(50f, 50f)lineTo(150f, 50f)lineTo(100f, 150f)close() // 闭合路径
}drawPath(path = path,color = Color.Magenta,style = Fill // 填充
)// 或描边
drawPath(path = path,color = Color.Black,style = Stroke(width = 3f)
)

1.3 文本

drawIntoCanvas { canvas ->val paint = Paint().apply {color = Color.BlacktextSize = 24.sp.toPx()textAlign = android.graphics.Paint.Align.CENTER}canvas.nativeCanvas.drawText("Hello Canvas",size.width / 2,size.height / 2,paint)
}

2. 样式控制
2.1 画笔样式

// 填充样式
drawCircle(color = Color.Red,radius = 50f,style = Fill
)// 描边样式
drawCircle(color = Color.Blue,radius = 60f,style = Stroke(width = 5f)
)// 描边+圆角
drawCircle(color = Color.Green,radius = 70f,style = Stroke(width = 10f,cap = StrokeCap.Round, // 圆角端点join = StrokeJoin.Round // 圆角连接)
)

2.2 渐变

// 线性渐变
val brush = LinearGradientBrush(start = Offset(0f, 0f),end = Offset(size.width, size.height),colors = listOf(Color.Red, Color.Blue)
)drawRect(brush = brush, size = size)// 径向渐变
val radialBrush = RadialGradientBrush(center = Offset(size.width / 2, size.height / 2),radius = size.minDimension / 2,colors = listOf(Color.Yellow, Color.Transparent)
)drawCircle(brush = radialBrush, radius = size.minDimension / 2)

3. 变换操作
3.1 平移、旋转、缩放

withTransform({translate(left = 50f, top = 50f) // 平移rotate(degrees = 45f) // 旋转scale(scaleX = 1.5f, scaleY = 1.5f) // 缩放
}) {drawCircle(color = Color.Red, radius = 30f)
}

3.2 裁剪

// 裁剪为圆形区域
clipPath(Path().apply {addOval(Rect(left = size.width / 4,top = size.height / 4,right = size.width * 3 / 4,bottom = size.height * 3 / 4))
}) {drawRect(color = Color.Blue, size = size)
}

4. 组合效果

4.1 阴影

drawCircle(color = Color.Red,radius = 50f,shadowColor = Color.Black.copy(alpha = 0.5f),blurRadius = 10f,style = Fill
)

4.2 混合模式

drawIntoCanvas { canvas ->canvas.saveLayer(Rect(0f, 0f, size.width, size.height), null)    // 绘制底层drawCircle(color = Color.Red, radius = 60f)  // 设置混合模式canvas.nativeCanvas.compositeMode = PorterDuff.Mode.SRC_IN   // 绘制上层drawCircle(color = Color.Blue, radius = 40f)canvas.restore()
}

栗子:

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp@Composable
fun GridBackground(cellSize: Dp = 30.dp,lineColor: Color = Color.LightGray.copy(alpha = 0.5f),lineWidth: Float = 1f
) {val cellPx = cellSize.valueCanvas(modifier = Modifier.fillMaxSize()) {val width = size.widthval height = size.height// 绘制水平线for (y in 0..height.toInt() step cellPx.toInt()) {drawLine(color = lineColor,start = Offset(0f, y.toFloat()),end = Offset(width, y.toFloat()),strokeWidth = lineWidth)}// 绘制垂直线for (x in 0..width.toInt() step cellPx.toInt()) {drawLine(color = lineColor,start = Offset(x.toFloat(), 0f),end = Offset(x.toFloat(), height),strokeWidth = lineWidth)}// 绘制对角线drawLine(color = lineColor,start = Offset(0f, 0f),end = Offset(width, height),strokeWidth = lineWidth)drawLine(color = lineColor,start = Offset(width, 0f),end = Offset(0f, height),strokeWidth = lineWidth)}
}
import androidx.compose.animation.core.*
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch@Composable
fun RippleEffect() {val scope = rememberCoroutineScope()val ripples = remember { mutableStateListOf<Ripple>() }LaunchedEffect(Unit) {while (true) {delay(1000)val ripple = Ripple()ripples.add(ripple)// 在协程中启动动画scope.launch {ripple.animatable.animateTo(targetValue = 1f,animationSpec = tween(2000, easing = LinearEasing))}if (ripples.size > 3) {ripples.removeAt(0)}}}Canvas(modifier = Modifier.fillMaxSize()) {val center = Offset(size.width / 2, size.height / 2)ripples.forEach { ripple ->val radius = ripple.animatable.value * size.minDimension * 0.3fval alpha = 1f - ripple.animatable.valueif(radius>0) {drawCircle(brush = Brush.radialGradient(colors = listOf(Color(0xFF42A5F5).copy(alpha = alpha * 0.7f),Color(0xFF42A5F5).copy(alpha = 0f)),center = center,radius = radius),radius = radius,center = center)}}}
}

注意:
1 避免阻塞UI线程,复杂计算应在后台协程中进行,只将结果传递给Canvas;
2 动画必须在协程中运行,Animatable、animate*AsState需在协程作用域内启动;
3 避免在绘制过程中创建对象,每次重组都会调用draw方法,应避免在其中创建新对象;

http://www.xdnf.cn/news/7163.html

相关文章:

  • 项目:在线音乐播放服务器——基于SSM框架和mybatis
  • redis持久化和数据淘汰方案
  • NB-IoT技术深度解析:部署模式与节能机制全指南
  • SONiC系统之高速数据遥测High Frequency Telemetry
  • Java中的伪共享(False Sharing):隐藏的性能杀手与高并发优化实战
  • Python训练营---Day29
  • 劳特巴赫trace32自定义调试界面
  • mysql的高可用
  • 基于MCP的AI Agent应用开发实践
  • 类的加载过程详解
  • 如何本地部署Qwen3系列的大小模型235B/32B并进行推理服务及并发测试?
  • 力扣1991:找到数组的中间位置(前缀和)
  • 三、关系数据库
  • leetcode报错原因总结需要背下来的程序片 [更新中]
  • MinIO:从入门到精通,解锁云原生存储的奥秘
  • 程序代码篇---python向http界面发送数据
  • Ubuntu搭建TFTP服务器的方法
  • OpenCL C++图像纹理处理
  • jvm安全点(四)openjdk17 c++源码垃圾回收之安全点轮询页内存设置不可访问
  • 前端图片上传组件实战:从动态销毁Input到全屏预览的全功能实现
  • 备份C#的两个类
  • 【DAY22】 复习日
  • 三、高级攻击工具与框架
  • React Flow 边的基础知识与示例:从基本属性到代码实例详解
  • 飞机飞行控制系统补偿模型辨识报告
  • HarmonyOS AVPlayer 音频播放器
  • 【2025软考高级架构师】——2022年11月份真题与解析
  • 【方法论】如何构建金字塔框架
  • C++ for QWidget:connect(连接)
  • C++ asio网络编程(8)处理粘包问题