原文连接:blog.jetbrains.com/kotlin/2021…html
Compose Multiplatform 的发布标志着使用 Kotlin 开发统一的 UI 支持又迈进了新一步!java
基于 Google 发布的 Jetpack Compose Android 1.0 稳定版 的前提 :android
Compose for Desktop 和 Compose for Web 已经升级为 Alpha 版本,它们的版本控制如今在 Compose Multiplatform 下保持一致,从而可使用相同的 artifacts 构建 Android、Desktop 和 Web UI。git
IDE 管理应用 JetBrains Toolbox App 已完成迁移到 Compose for Desktop。github
IntelliJ IDEA 和 Android Studio 的新插件 经过@Preview
注释能够启用 Compose for Desktop 的组件预览。web
Compose for Desktop 如今默认使用可组合 API Window ,提供对自适应窗口大小、统一图像资源的新支持,以及对 ARM64 上 Linux 的新平台支持,容许在 Raspberry Pi 等目标上运行它。api
Compose for Web 进一步扩展了 DOM 和 CSS API。浏览器
另外在 The Compose Story 中 概述了 Compose 的路径,并分享了更多声明式多平台用户界面的信息!安全
Jetpack Compose 是一个为 Android 构建原生用户界面的响应式开发 UI 框架,JetBrains 在 Google 的 Jetpack Compose 的基础上将 Compose 框架拓展到更多新的平台。服务器
借助 Compose Multiplatform,开发者可使用和 Android Jetpack Compose 相同的 API 开发 Desktop 和 Web 构建用户界面。
使用 Kotlin Multiplatform 提供的机制,如今能够针对同一项目中的如下任意组合:
之前 Compose for Desktop 和 Compose for Web 使用不一样的 artifacts ,而如今开始它们将统一在一个 Gradle 插件和组件下,这意味着基于 Compose 开发 Android、Desktop 和 Web 用户界面会更容易。
凭借 Alpha 版本的更新,Compose Multiplatform 提供的 API 已经很接近其最终形态,咱们将全力投入 Compose 的开发支持,并指望在 2021 年内能达到 1.0 版本,更多详细信息:了解有关 COMPOSE 多平台的更多信息
在 JetBrains 如今一些生产应用已经开始采用 Compose,首先是 JetBrains Toolbox App,它是 JetBrains IDE 的管理应用程序,每个月活跃用户超过 800,000。
在它们的最新版本中,该团队已将应用程序的实现彻底转换为 Compose for Desktop,在从基于 Electron 的 UI 迁移期间,团队注意到了 Compose 的许多优点:
JetBrains Toolbox 团队负责人 Victor Kropp 也在帖子中分享了他对 Compose for Desktop 的见解:
Compose for Desktop 虽然仍处于早期阶段,但已被证明了 Toolbox App 的绝佳选择。在开发框架同事的支持下,几乎能够在短期内重写整个 UI。这使咱们可以统一开发体验,所以从业务逻辑到 UI,从应用到服务器,Toolbox 如今 100% 是 Kotlin。
在此版本中还发布了一个新的 IDE 插件来支持开发工做:用于 IntelliJ IDEA 和 Android Studio 的 Compose Multiplatform 插件,它与框架的新版本一块儿发布,并提供额外的功能来帮助用户界面的开发工做。
第一个版本包括了一项期待已久的功能:可以直接在 IDE 中预览 Compose for Desktop 和 Android 组件,甚至无需启动应用程序。
要显示@Composable
不带参数的函数预览,能够将@Preview
注释添加到其定义中,这时候会添加一个小的装订线图标,可使用它来切换组件的预览窗格:
这个新的预览版能够帮助开发者缩短开发周期,并更轻松地将想法转化为基于 Compose 的真实设计和布局。
要查找并安装新插件,请在插件市场中搜索“Compose Multiplatform IDE Support”,或点击下方直接打开插件页面:安装 COMPOSE 多平台插件
除了将 Compose for Desktop 升级为 Alpha 的一大步以外,在此版本中还改进了其 API 并增长了对新平台的支持。
在里程碑4桌面版中,咱们推出了一个实验组API:Window
,MenuBar
和Tray
,这些新 API 都使用 @Composable
与应用程序中的其余组件相同的状态管理、行为和条件呈现概念。
在此版本中,这些可组合版本如今是管理窗口、菜单栏和托盘图标的默认方式,取代了旧的窗口 API。
若是尚未尝试过这些新 API,或者只是想了解有关它们提供的行为和功能的更多信息,能够参考更新的 Compose for Desktop 教程,了解窗口和托盘管理。
有时咱们想将某些内容做为一个总体显示,而在不事先知道将显示的内容的状况下,这意味着咱们不知道它的最佳窗口尺寸。
为了更轻松地开发这些 UI 场景,咱们引入了自适应窗口大小功能,经过将窗口的一个或两个维度设置WindowSize
为 Dp.Unspecified
,Compose for Desktop 将自动调整该维度中窗口的初始大小以适应其内容:
fun main() = application {
val state = rememberWindowState(width = Dp.Unspecified, height = Dp.Unspecified) //automatic size
Window(
onCloseRequest = ::exitApplication,
state = state,
title = "Adaptive",
resizable = false
) {
Column(Modifier.background(Color(0xFFEEEEEE))) {
Row {
Text("label 1", Modifier.size(100.dp, 100.dp).padding(10.dp).background(Color.White))
Text("label 2", Modifier.size(150.dp, 200.dp).padding(5.dp).background(Color.White))
Text("label 3", Modifier.size(200.dp, 300.dp).padding(25.dp).background(Color.White))
}
}
}
}
复制代码
连同删除窗口(经过undecorated = true
的应用程序Window
定义),咱们相信这种建立动态大小窗口的新方法,为各类形状和大小的用户界面新增了额外的可能性。
桌面应用一般带有丰富而复杂的窗口菜单。在此版本中还添加了容许建立丰富菜单的其余 API。
它们能够被结构化,经过图标、快捷方式和助记符来丰富,并集成普遍使用的复选框和单选列表(单选按钮)的逻辑:
@OptIn(ExperimentalComposeUiApi::class)
@Composable
private fun MenuBarScope.FileMenu() = Menu("Settings", mnemonic = 'S') {
Item(
"Reset",
mnemonic = 'R',
shortcut = KeyShortcut(Key.R, ctrl = true),
onClick = { println("Reset") }
)
CheckboxItem(
"Advanced settings",
mnemonic = 'A',
checked = isAdvancedSettings,
onCheckedChange = { isAdvancedSettings = !isAdvancedSettings }
)
if (isAdvancedSettings) {
Menu("Theme") {
RadioButtonItem(
"Light",
mnemonic = 'L',
icon = ColorCircle(Color.LightGray),
selected = theme == Theme.Light,
onClick = { theme = Theme.Light }
)
RadioButtonItem(
"Dark",
mnemonic = 'D',
icon = ColorCircle(Color.DarkGray),
selected = theme == Theme.Dark,
onClick = { theme = Theme.Dark }
)
}
}
}
复制代码
Compose for Desktop Alpha 支持默认和自定义上下文菜单,能够经过单击鼠标右键触发。
对于可选择的文本和文本字段,该框架提供了一组默认的上下文菜单项,让用户能够复制、粘贴、剪切和选择。
@OptIn(ExperimentalComposeUiApi::class, androidx.compose.foundation.ExperimentalFoundationApi::class)
fun main() = singleWindowApplication(title = "Context menu") {
DesktopMaterialTheme { //it is mandatory for Context Menu
val text = remember {mutableStateOf("Hello!")}
ContextMenuDataProvider(
items = {
listOf(ContextMenuItem("Clear") { text.value = "" })
}
) {
TextField(
value = text.value,
onValueChange = { text.value = it },
label = { Text(text = "Input") }
)
}
}
}
复制代码
在此版本的 Compose for Desktop 开始,当鼠标悬停在文本字段或可选文本上时,鼠标指针如今会自动变成文本选择光标,表示能够进行文本选择,使应用感受更加贴近原生。
对于本身的组件,还可使用新添加的 pointerIcon
修饰符来调整鼠标指针的行为,能够在将鼠标悬停在特定组件上时更改指针。
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun ApplicationScope.pointerIcons() {
Window(onCloseRequest = ::exitApplication, title = "Pointer icons") {
Text(
modifier = Modifier.pointerIcon(PointerIcon.Hand),
text = "Hand icon!"
)
}
}
复制代码
为了更方便处理在鼠标单击时单击或按下的鼠标按钮和键盘修饰键,这里引入了一个带有.mouseClickable
修饰符的新 API 。
将此修饰符添加到组件就能够容许指定接收 MouseClickScope
的回调,它提供了有关事件的完整信息:
@ExperimentalDesktopApi
@Composable
fun ApplicationScope.mouseClickable() {
Window(onCloseRequest = ::exitApplication, title = "mouseClickable") {
Box {
var clickableText by remember { mutableStateOf("Click me!") }
Text(
modifier = Modifier.mouseClickable(
onClick = {
if (buttons.isPrimaryPressed && keyboardModifiers.isShiftPressed) {
clickableText = "Shift + left-mouse click!"
} else {
clickableText = "Wrong combination, try again!"
}
}
),
text = clickableText
)
}
}
}
复制代码
请注意,这个 API 还不是最终版本,目前正在继续开发,未来可能会改变它。
在进一步稳定 Compose for Desktop 的 API 的过程当中,如今可使用统一的 painterResource
,而不是将图形资源分红 svgResource
、 imageResource
、vectorXmlResource
:
@Composable
fun ApplicationScope.painterResource() {
Window(onCloseRequest = ::exitApplication, title = "Image resources") {
Column {
Image(
painter = painterResource("sample.svg"), // Vector
contentDescription = "Sample",
modifier = Modifier.fillMaxSize()
)
Image(
painter = painterResource("sample.xml"), // Vector
contentDescription = "Sample",
modifier = Modifier.fillMaxSize()
)
Image(
painter = painterResource("sample.png"), // ImageBitmap
contentDescription = "Sample",
modifier = Modifier.fillMaxSize()
)
}
}
}
复制代码
咱们还将 window icon
属性从 java.awt.Image
更改成androidx.compose.ui.graphics.painter.Painter
,所以除了将来的光栅图形以外,还可使用基于矢量的图标:
fun vectorWindowIcon() {
application {
var icon = painterResource("sample.svg") //vector icon
Window(onCloseRequest = ::exitApplication, icon = icon) {
Text("Hello world!")
}
}
}
复制代码
在此版本中,除了现有的 x86-64 支持以外,Compose for Desktop 还增长了对运行在基于 ARM64 处理器的设备上的 Linux 的支持。
总的来讲,如今可使用 Compose for Desktop 为如下平台编写 UI:
除了 Compose for Desktop,Compose for Web 也已升级为 Alpha 版本,二者都已经调整了版本控制方案和发布周期,并经过他们的 DSL 扩展了可用的功能,用于样式和事件管理。
咱们将继续改进和完善 API,以经过 CSS 指定样式规则,这个最新版本在类型安全的 DSL 中增长了对算术运算、设置属性和动画的更好支持。
如今能够对 CSS 数值执行任意操做,若是对相同单位的两个值使用运算,将得到相同单位的新值,以下例所示:
val a = 5.px
val b = 20.px
borderBottom(a + b) // 25px
复制代码
扩展了对全部最经常使用的 CSS 属性的类型安全访问,并涵盖了大部分的现代浏览器支持的全部 CSS 属性。
这意味着在大多数状况下可以直接从类型安全的 API 中得到支持,而对于更奇特的属性,或尚不支持的属性,还能够经过property
直接获取键和值的函数进行赋值:
borderWidth(topLeft = 4.px, bottomRight = 10%) // type-safe access!
property("some-exotic-property", "hello-friend") // raw property assignment
复制代码
为了使基于 Compose 的用户界面更加动态,如今提供了从类型安全的 DSL 中建立 CSS 动画的选项:
object AppStyleSheet : StyleSheet() {
val bounce by keyframes {
from {
property("transform", "translateX(50%)")
}
to {
property("transform", "translateX(-50%)")
}
}
val myClass by style {
animation(bounce) {
duration(2.s)
timingFunction(AnimationTimingFunction.EaseIn)
direction(AnimationDirection.Alternate)
}
}
}
复制代码
若是想本身更多地探索这些 API,请务必查看咱们新添加的示例,这些示例展现了一些更高级的 CSS 动画和 DOM 操做功能。
处理事件,尤为是由输入组件发出的事件,是对 Compose 应用程序中的更改作出反应的关键部分之一。
在此版本中简化了对事件属性的访问,使其更容易定义事件侦听器,并提供了不一样的输入类型。
之前大多数基于事件的 API 要求直接使用nativeEvent
或 eventTarget
以访问感兴趣的事件的值。
今后版本的 Compose for Web 开始,您如今能够访问 a SyntheticEvent
,其子类型使其更容易访问所发出事件的相关属性。
SyntheticMouseEvent
公开坐标;SyntheticInputEvent
公开文本值;SyntheticKeyEvent
公开 click 键举几个例子:
Div(attrs = {
onClick { event -> // SyntheticMouseEvent
val x = event.x
val y = event.y
}
})
复制代码
这些新事件类型旨在直接提供对 在 Native 事件中可用 相同的属性的访问,而无需访问 nativeEvent
或直接事件的目标。
在常规 HTML 中,不一样的输入类型,从文本字段到复选框都共享同一个标签——输入。
为了更轻松地在 Kotlin DSL 中使用这些不一样的输入类型并提供更多相关提示,这里引入了许多用于建立不一样类型输入的附加函数:
TextInput(value = "text", attrs = {
onInput { } // all these components have attrs same as HTMLInputElement
})
CheckboxInput(checked = false)
RadioInput(checked = false)
NumberInput(value = 0, min = 0, max = 10)
DateInput(value = 2021-10-10") TelInput(value = "0123456") EmailInput() // and other input types 复制代码
进一步统一了用于监听不一样输入类型事件的函数。
输入侦听器的输入类型特定函数 onCheckBoxInput
已被删除,如今能够直接使用 onInput
或onChange
,这意味着再也不须要搜索正确命名的回调:
Input(type = InputType.Text, attrs = {
onInput { event ->
val inputValue: String = event.value
}
})
Input(type = InputType.Checkbox, attrs = {
onInput { event ->
val isChecked: Boolean = event.value
}
})
复制代码
不管是 Web、桌面、Android 仍是这三者,咱们都但愿你能尝试一下 Compose Multiplatform!
咱们预计 Compose Multiplatform 1.0(咱们的第一个稳定版本)将于今年晚些时候发布,所以如今是尝试为您的生产应用评估 Compose Multiplatform 的理想时机。
这里有有许多可用资源:
对于桌面应用程序,能够在Compose for Desktop 教程 中找到有关如何开始使用的最新信息。
对于浏览器应用程序,Compose for Web 教程将帮助启动和运行。
示例应用程序展现包括要研究的其余示例,包括 Web、桌面和多平台应用程序。
Compose Multiplatform 目前处于 Alpha 阶段 ,虽然大多数 API 如今已经很是相似于它们的稳定形状,但请记住仍可能会更改某些 API,以确保最终版本提供尽量最佳的开发体验。
随着接近稳定版本,咱们将继续依靠用户的反馈来帮助实现这一目标!