Kotlin Compose 04 控件 Image
文章目录
文档地址
简单说明
首先,代码部分,我会以 LazyColumn
作为 App
的根容器,这个容器可以简单理解为 ScrollView
和 ListView
的混合体,后面会详细说
然后每一个子元素会被包裹在一个 item {}
闭包内,但每一个都包的话,很不oop,所以,我会略微封装一下,变成下面这样,这样我就可以直接在 MyColumn
闭包内写每一个item了
1@Composable
2fun App() {
3 var text by remember { mutableStateOf("Hello, World!") }
4 val platformName = getPlatformName()
5
6 MyColumn {
7 Button(onClick = {
8 text = "Hello, $platformName"
9 }) {
10 Text(text)
11 }
12 }
13
14}
15
16@Composable
17fun MyColumn(content: @Composable LazyItemScope.() -> Unit) {
18 LazyColumn {
19 item {
20 content()
21 }
22 }
23}
加载资源图片
compose
的图片是依托于 androidx.compose.foundation.Image
控件来显示的
一个入门级的示例
1package top.kikt.common.image
2
3import androidx.compose.foundation.Image
4import androidx.compose.foundation.layout.width
5import androidx.compose.runtime.Composable
6import androidx.compose.ui.Modifier
7import androidx.compose.ui.graphics.ImageBitmap
8import androidx.compose.ui.graphics.painter.Painter
9import androidx.compose.ui.graphics.vector.ImageVector
10import androidx.compose.ui.res.loadImageBitmap
11import androidx.compose.ui.res.loadSvgPainter
12import androidx.compose.ui.res.loadXmlImageVector
13import androidx.compose.ui.res.painterResource
14import androidx.compose.ui.unit.Density
15import androidx.compose.ui.unit.dp
16import org.xml.sax.InputSource
17import java.io.File
18import java.net.URL
19
20@Composable
21actual fun ImageExample() {
22 Image(
23 painter = painterResource("header.svg"), // 支持格式:(BMP, GIF, HEIF, ICO, JPEG, PNG, WBMP, WebP) and vector formats (SVG, XML vector drawable).
24 contentDescription = "Sample", // 用于无障碍
25 modifier = Modifier.size(200.dp, 200.dp), // 设置约束
26 contentScale = ContentScale.FillBounds, // 设置缩放模式
27 )
28}
painterResource 支持的格式很多
supports raster (BMP, GIF, HEIF, ICO, JPEG, PNG, WBMP, WebP) and vector formats (SVG, XML vector drawable ).
异步加载图片
官方给的一个示例,用于使用 io 加载网络图片或 java 的本地文件
1import androidx.compose.foundation.Image
2import androidx.compose.foundation.layout.Column
3import androidx.compose.foundation.layout.width
4import androidx.compose.runtime.Composable
5import androidx.compose.runtime.getValue
6import androidx.compose.runtime.produceState
7import androidx.compose.runtime.remember
8import androidx.compose.ui.Modifier
9import androidx.compose.ui.graphics.ImageBitmap
10import androidx.compose.ui.graphics.painter.BitmapPainter
11import androidx.compose.ui.graphics.painter.Painter
12import androidx.compose.ui.graphics.vector.ImageVector
13import androidx.compose.ui.graphics.vector.rememberVectorPainter
14import androidx.compose.ui.layout.ContentScale
15import androidx.compose.ui.platform.LocalDensity
16import androidx.compose.ui.res.loadImageBitmap
17import androidx.compose.ui.res.loadSvgPainter
18import androidx.compose.ui.res.loadXmlImageVector
19import androidx.compose.ui.unit.Density
20import androidx.compose.ui.unit.dp
21import androidx.compose.ui.window.singleWindowApplication
22import kotlinx.coroutines.Dispatchers
23import kotlinx.coroutines.withContext
24import org.xml.sax.InputSource
25import java.io.File
26import java.io.IOException
27import java.net.URL
28
29fun main() = singleWindowApplication {
30 val density = LocalDensity.current
31 Column {
32 AsyncImage(
33 load = { loadImageBitmap(File("sample.png")) },
34 painterFor = { remember { BitmapPainter(it) } },
35 contentDescription = "Sample",
36 modifier = Modifier.width(200.dp)
37 )
38 AsyncImage(
39 load = { loadSvgPainter("https://github.com/JetBrains/compose-jb/raw/master/artwork/idea-logo.svg", density) },
40 painterFor = { it },
41 contentDescription = "Idea logo",
42 contentScale = ContentScale.FillWidth,
43 modifier = Modifier.width(200.dp)
44 )
45 AsyncImage(
46 load = { loadXmlImageVector(File("compose-logo.xml"), density) },
47 painterFor = { rememberVectorPainter(it) },
48 contentDescription = "Compose logo",
49 contentScale = ContentScale.FillWidth,
50 modifier = Modifier.width(200.dp)
51 )
52 }
53}
54
55@Composable
56fun <T> AsyncImage(
57 load: suspend () -> T,
58 painterFor: @Composable (T) -> Painter,
59 contentDescription: String,
60 modifier: Modifier = Modifier,
61 contentScale: ContentScale = ContentScale.Fit,
62) {
63 val image: T? by produceState<T?>(null) {
64 value = withContext(Dispatchers.IO) {
65 try {
66 load()
67 } catch (e: IOException) {
68 // instead of printing to console, you can also write this to log,
69 // or show some error placeholder
70 e.printStackTrace()
71 null
72 }
73 }
74 }
75
76 if (image != null) {
77 Image(
78 painter = painterFor(image!!),
79 contentDescription = contentDescription,
80 contentScale = contentScale,
81 modifier = modifier
82 )
83 }
84}
85
86/* Loading from file with java.io API */
87
88fun loadImageBitmap(file: File): ImageBitmap =
89 file.inputStream().buffered().use(::loadImageBitmap)
90
91fun loadSvgPainter(file: File, density: Density): Painter =
92 file.inputStream().buffered().use { loadSvgPainter(it, density) }
93
94fun loadXmlImageVector(file: File, density: Density): ImageVector =
95 file.inputStream().buffered().use { loadXmlImageVector(InputSource(it), density) }
96
97/* Loading from network with java.net API */
98
99fun loadImageBitmap(url: String): ImageBitmap =
100 URL(url).openStream().buffered().use(::loadImageBitmap)
101
102fun loadSvgPainter(url: String, density: Density): Painter =
103 URL(url).openStream().buffered().use { loadSvgPainter(it, density) }
104
105fun loadXmlImageVector(url: String, density: Density): ImageVector =
106 URL(url).openStream().buffered().use { loadXmlImageVector(InputSource(it), density) }
107
108/* Loading from network with Ktor client API (https://ktor.io/docs/client.html). */
109
110/*
111
112suspend fun loadImageBitmap(url: String): ImageBitmap =
113 urlStream(url).use(::loadImageBitmap)
114
115suspend fun loadSvgPainter(url: String, density: Density): Painter =
116 urlStream(url).use { loadSvgPainter(it, density) }
117
118suspend fun loadXmlImageVector(url: String, density: Density): ImageVector =
119 urlStream(url).use { loadXmlImageVector(InputSource(it), density) }
120
121@OptIn(KtorExperimentalAPI::class)
122private suspend fun urlStream(url: String) = HttpClient(CIO).use {
123 ByteArrayInputStream(it.get(url))
124}
125
126 */
这里使用了 withContext ,也就是协程来加载图片,然后将 inputStream 传给官网提供的对应方法来加载图片为Painter
Canvas 类“图片”
其实称呼这种为图片不太准确,只是 Canvas 支持将图片写到画布上而已
1package top.kikt.common.image
2
3import androidx.compose.runtime.Composable
4import androidx.compose.foundation.Canvas
5import androidx.compose.foundation.layout.size
6import androidx.compose.runtime.remember
7import androidx.compose.ui.Modifier
8import androidx.compose.ui.geometry.Offset
9import androidx.compose.ui.graphics.*
10import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
11import androidx.compose.ui.unit.IntOffset
12import androidx.compose.ui.unit.IntSize
13import androidx.compose.ui.unit.dp
14
15@Composable
16fun ImageExample() {
17 ResImageExample()
18 CanvasImageExample()
19}
20
21@Composable
22fun CanvasImageExample() {
23 val image = Logo()
24
25 Canvas(modifier = Modifier.size(100.dp, 100.dp)) {
26 val redPaint = Paint().apply {
27 color = Color.Red
28 }
29 val bluePaint = Paint().apply {
30 color = Color.Blue
31 }
32 val greenPaint = Paint().apply {
33 color = Color.Green
34 }
35 drawIntoCanvas { canvas: Canvas ->
36 canvas.withSave {
37 canvas.drawCircle(Offset(100f, 100f), 100f, redPaint)
38 canvas.drawCircle(Offset(100f, 100f), 66f, bluePaint)
39 canvas.drawCircle(Offset(100f, 100f), 33f, greenPaint)
40 }
41 }
42 }
43
44 Canvas(modifier = Modifier.size(400.dp, 400.dp)) {
45 drawIntoCanvas {
46 it.withSave {
47 it.drawImageRect(
48 image,
49 IntOffset(0, 0),
50 IntSize(image.width, image.height),
51 IntOffset(0, 0),
52 IntSize(400, 400),
53 Paint(),
54 )
55 }
56 }
57 }
58}
设置窗口图标
所谓Icon,指的是这个
macOS 上如果是debug运行可以通过最小化窗口来查看
设置
窗口图标是通过设置 Window 的 icon 属性来配置的 Painter 的实现类有这些,理论上可以通过任意一个来实现,支持位图
最简单的,可以设置纯色
1package top.kikt.image
2
3import androidx.compose.runtime.Composable
4import androidx.compose.ui.graphics.Color
5import androidx.compose.ui.graphics.painter.ColorPainter
6import androidx.compose.ui.graphics.painter.Painter
7
8@Composable
9fun ImageIconPainter(): Painter {
10 return ColorPainter(Color.Blue)
11}
菜单栏图标设置
菜单栏就是这个东西,WIndows 应该是右下角任务栏的那个图标 代码如下
1package top.kikt.image
2
3import androidx.compose.runtime.Composable
4import androidx.compose.ui.graphics.painter.BitmapPainter
5import androidx.compose.ui.window.ApplicationScope
6import androidx.compose.ui.window.Tray
7
8@Composable
9fun ApplicationScope.TrayWindowPaint() {
10 val icon = Logo()
11 Tray(
12 icon = BitmapPainter(icon),
13 menu = {
14 Item("Quit App", onClick = ::exitApplication)
15 },
16 )
17}
这里是使用了扩展方法来定义的,因为Tray方法本身是 ApplicatioinScope 的扩展方法,为了在单独文件内定义控件,所以这里使用这种定义方法
menu 就是定义弹出的选项, 使用 Item 方法来定义每个选项即可