Jetpack Compose for Desktop 初体验

在这里插入图片描述
就在上个月Jetpack Compose for Desktop正式发布。未来通过使用Compose可以在macOS/Linux/Windows等平台像,Flutter、React那样进行声明式UI开发了,而且是使用Kotlin语言。这对于广大Android开发者是一个福音。

有兴趣的同学可以前去 Compose for Desktop, by JetBrains 进行体验。本文针对项目的Sample做一个介绍

运行环境


  • macOS Catalina 10.15.7
  • IntelliJ IDEA 2020.3 (Community Edition)
  • AdoptOpenJDK 14.0.2
  • Kotlin 1.4.20
  • Desktop Compose 0.2.0-build132

1. 图片


fun main() {
    
    
    Window {
    
    
        Image(
            bitmap = TODO("Create ImageBitmap"),
            modifier = Modifier.fillMaxSize()
        )
    }
}

Create ImageBitmap有以下几种方法:

1.1 从Resource中加载

从Resource目录中加载图片

bitmap = imageResource("sample.png"),

注意imageResource@Composable函数,只能在@Composable中调用。

除了png等一般图片外,还可以加载xml格式的矢量图,此时需要使用vectorXmlResource方法

imageVector = vectorXmlResource("images/compose-logo.xml"),

1.2 从Device加载

从设备的指定路径中加载图片文件

bitmap = Image.makeFromEncoded(File("sample.png").readBytes()).asImageBitmap(),

1.3 Canvas绘制

除了加载资源外,也可以直接在Canvas上绘制图片。例子比较长,此处省略。


2. APP图标


创建APP窗口的Window时,可以指定APP图标

fun main() {
    
    
    Window(icon = ImageIO.read(File("sample.png"))) {
    
    
    }
}

3.托盘图标

在onActive中可以设置系统托盘图标,menu必须设置否则无法显示

fun main() {
    
    
    Window {
    
    
        onActive {
    
    
            val tray = Tray().apply {
    
    
                icon(ImageIO.read(File("sample.png")))
                menu(
                    MenuItem(
                        name = "Quit App",
                        onClick = {
    
     AppManager.exit() }
                    )
                )
            }
            onDispose {
    
    
                tray.remove()
            }
        }
    }
}

4. 滚动条

Scrollbar的显示至少要完成以下配置:

fun main() {
    
    
    Window {
    
    
        Box {
    
    
            val stateVertical = rememberScrollState(0f)
            val stateHorizontal = rememberScrollState(0f)

            ScrollableColumn(scrollState = stateVertical) {
    
    
                ScrollableRow(scrollState = stateHorizontal) {
    
    
                    Column {
    
    
                        for (item in 0..100) {
    
    
                            Box {
    
     Text("Item in ScrollableColumn #$item") }
                        }
                    }
                }
            }
            VerticalScrollbar(adapter = rememberScrollbarAdapter(stateVertical))
            HorizontalScrollbar(adapter = rememberScrollbarAdapter(stateHorizontal))
        }
    }
}
  1. Compose是基于State驱动的,所以需要通过 rememberScrollState()为各个滚动条创建ScrollState
  2. 将创建的state传递给ScrollableColumnScrollableRow
  3. 通过 rememberScrollbarAdapter(scrollState: ScrollState)创建ScrollAdapter
  4. 将adapter传递给Scrollbar

5. 鼠标事件


在UI中通过Modifier.clickable监听鼠标的Click事件回调

5.1 Click事件

Box(
    modifier = Modifier.clickable(
        onClick = {
    
    
        },
        onDoubleClick = {
    
    
        },
        onLongClick = {
    
    
        }
    )
)

5.2 鼠标移动

Modifier.pointerMoveFilter监听鼠标移动

Box(
    modifier = Modifier.pointerMoveFilter(
        onMove = {
    
    
            false
        },
        onEnter = {
    
    
            false
        },
        onExit = {
    
    
            false
        }
    )
)
  • onMove: 获取鼠标当前坐标
  • onEnter: 鼠标进入此View的区域
  • onExit: 鼠标移除此区域

6 键盘事件


下面的例子中,我们在TextField中输入的文字通过Cmd+Enter 会出现在上面Text"Apply text:"中;通过"Cmd+R"会清空Text

@OptIn(ExperimentalKeyInput::class)
fun main() = Window {
    
    
    MaterialTheme {
    
    
        var applyText by remember {
    
     mutableStateOf("") }
        var inputText by remember {
    
     mutableStateOf("") }
        Column {
    
    
            Text("Apply text: $applyText")
            TextField(
                value = inputText,
                onValueChange = {
    
     inputText = it },
                modifier = Modifier.shortcuts {
    
    
                    on(Key.CtrlLeft + Key.Enter) {
    
    
                        applyText = inputText
                        inputText = ""
                    }
                    on(Key.CtrlLeft + Key.R) {
    
    
                        applyText = ""
                        inputText = ""
                    }
                }
            )
        }
    }
}

KeyInut相关的API目前还是Experimental状态,后期有可能会变化,需注意。

另外,通过AppWindowkeyboard属性,可以定义一些全局快捷键,如下:

AppWindow().also {
    
    
    it.keyboard.setShortcut(Key.Escape) {
    
    
        it.close()
    }
}.show {
    
    
}

7. 兼容Java Swing


Swing是我们常用的桌面端GUI库,Compose可以再Swing中使用,ComposePanel可以了使用Compose的容器:

fun main() {
    
    
    val window = JFrame()
    val composePanel = ComposePanel()
    window.contentPane.add(composePanel, BorderLayout.CENTER)
    composePanel.setContent {
    
    
        Box {
    
    
            Text("text")
        }
    }
    window.setSize(100, 100)
    window.isVisible = true
}

最后


https://github.com/JetBrains/compose-jb/tree/master/tutorials
虽然Kotlin-Multiplatform在跨平台领域早已显露头角,但多是用于逻辑层,如今Compose的出现把UI层的短板也补齐了,这将大大提升Kotlin在跨平台领域的整体竞争力,对Kotlin的未来无限看好~

猜你喜欢

转载自blog.csdn.net/vitaviva/article/details/111730807