Compose Multiplatform 1.5.0 ya está disponible oficialmente. Toma el marco de interfaz de usuario declarativo Jetpack Compose para Kotlin y lo extiende desde Android al escritorio, iOS y la web. La versión de escritorio es estable, iOS está en Alpha y el soporte web aún es experimental. Para obtener instrucciones completas, consulte el sitio web de Compose Multiplatform .
Algunos aspectos destacados de esta versión incluyen:
Las API Dialog, Popup y WindowInsets ahora usan código común.
Para el desplazamiento de iOS, se han mejorado la gestión de recursos y los campos de texto.
El marco de prueba de la interfaz de usuario se ha estabilizado en el escritorio.
Esta versión se basa en Jetpack Compose 1.5 y se centra en mejoras de rendimiento. Al mismo tiempo, se basa en la versión 1.1 de Material Design 3 , incluidos nuevos componentes como el selector de fecha y el selector de hora.
Pruebe Compose Multiplataforma 1.5.0:
https://github.com/JetBrains/compose-multiplatform/releases/tag/v1.5.0
Redactar multiplataforma
Diálogo de soporte, ventanas emergentes y ventanas
A partir de la versión 1.5, los cuadros de diálogo y las ventanas emergentes están disponibles en Compose Multiplatform. Los cuadros de diálogo se utilizan para eventos modales donde el usuario realiza selecciones o ingresa datos. Mientras tanto, las ventanas emergentes se utilizan para comportamientos no modales, como proporcionar funcionalidad opcional.
En esta versión, los tipos base Dialog y Popup , así como DropdownMenu y AlertDialog son accesibles desde código universal. Esto evita la necesidad de proporcionar funcionalidades específicas de la plataforma.
Por ejemplo, el siguiente elemento componible está escrito completamente en código genérico:
@Composable
fun CommonDialog() {
var isDialogOpen by remember { mutableStateOf(false) }
Button(onClick = { isDialogOpen = true }) {
Text("Open")
}
if (isDialogOpen) {
AlertDialog(
onDismissRequest = { },
confirmButton = {
Button(onClick = { isDialogOpen = false }) {
Text("OK")
}
},
title = { Text("Alert Dialog") },
text = { Text("Lore ipsum") },
)
}
}
Cómo aparece en escritorio, Android e iOS:
La tercera característica disponible en esta versión es la API WindowInsets , que describe cuánto ajuste se necesita para evitar que el contenido se superponga a la interfaz de usuario del sistema. A partir de la versión 1.5, esta función está incluida en Compose Multiplatform y, por lo tanto, está disponible en Android e iOS.
Usando la API WindowInsets, el contenido de fondo se puede dibujar detrás de la muesca a través de Compose Multiplatform. No es necesario agregar una línea blanca en la parte superior de la aplicación. La diferencia se muestra en la siguiente captura de pantalla:
Mejoras en iOS
La plataforma iOS es el foco de esta versión e incluye una serie de mejoras. El desplazamiento imita la apariencia de la plataforma, la administración de recursos se simplifica y se mejora el manejo de texto.
desplazamiento natural
En esta versión, el desplazamiento de iOS se ajustó para imitar el desplazamiento nativo. Supongamos que la cantidad y/o el tamaño de los elementos que se mostrarán en su código excede el espacio disponible:
@Composable
fun NaturalScrolling() {
val items = (1..30).map { "Item $it" }
LazyColumn {
items(items) {
Text(
text = it,
fontSize = 30.sp,
modifier = Modifier.padding(start = 20.dp)
)
}
}
}
Al desplazarse, los elementos aparecerán en los bordes de la pantalla, al igual que la aplicación nativa de iPhone:
Soporte para fuentes dinámicas
Función de fuentes dinámicas en iOSPermita a los usuarios establecer tamaños de fuente preferidos: fuentes más grandes para una visualización más fácil, fuentes más pequeñas para más contenido. El tamaño del texto utilizado en su aplicación debe estar relacionado con esta configuración del sistema.
Compose Multiplatform ahora admite esta función. El incremento utilizado al escalar el texto es el mismo que se utiliza en las aplicaciones nativas, por lo que el comportamiento será el mismo.
Tome los siguientes elementos componibles como ejemplo:
@Composable
fun DynamicType() {
Text("This is some sample text", fontSize = 30.sp)
}
Pantalla con tamaño de lectura preferido establecido al mínimo:
Este es el resultado cuando el tamaño de lectura preferido es máximo:
Soporte para pantallas de alta frecuencia de actualización
En versiones anteriores, la velocidad de fotogramas máxima era de 60 FPS. Esto puede hacer que la interfaz de usuario sea lenta y retrasada en dispositivos con pantallas de 120 Hz. A partir de esta versión, las velocidades de fotogramas admitidas son de hasta 120 FPS.
Gestión de recursos simplificada
A partir de 1.5.0, todos los recursos de la carpeta de recursos de un conjunto de fuentes de iOS se copian en el paquete de aplicaciones de forma predeterminada. Por ejemplo, si coloca un archivo de imagen en src/commonMain/resources/
, se copiará en el paquete y estará disponible desde el código.
Cuando usa CocoaPods, ya no necesita configurar este comportamiento en el archivo de compilación de Gradle. Tampoco es necesario volver a llamar podInstall para asegurarse de que el recurso se copie después de la modificación.
A partir de esta versión, si intenta configurar el comportamiento explícitamente en el script de compilación (como se muestra a continuación), recibirá el error:
kotlin {
cocoapods {
extraSpecAttributes["resources"] = "..."
}
}
Para obtener detalles completos y orientación sobre cómo migrar el código existente, consulte este documento .
Campo de texto mejorado
En versiones anteriores, ingresar texto podía provocar un comportamiento inesperado en dos situaciones. A partir de esta versión, TextField
se han realizado mejoras para superar estos problemas.
Problemas del caso
En primer lugar, TextField
ahora se reconoce si la utilización automática de mayúsculas en las primeras letras está desactivada. Esto es especialmente importante al ingresar contraseñas. Puede controlar este comportamiento a través del argumento KeyboardOptions.
Para ilustrar esto, mire los elementos componibles a continuación:
fun TextFieldCapitalization() {
var text by remember { mutableStateOf("") }
TextField(
value = text,
onValueChange = { text = it },
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Sentences,
autoCorrect = false,
keyboardType = KeyboardType.Ascii,
),
)
}
La imagen de la izquierda muestra lo que sucede cuando el atributo en mayúsculas se establece en KeyboardCapitalization.None
, y la imagen de la derecha muestra KeyboardCapitalization.Sentences
lo que sucede cuando el valor es .
teclado físico
El segundo caso está relacionado con el teclado de hardware. En versiones anteriores, al usar un teclado de hardware, presionar Enter provocaría múltiples saltos de línea y presionar Retroceso provocaría múltiples eliminaciones. A partir de esta versión, estos eventos se manejan correctamente.
Mejoras de escritorio
Estabilizó el marco de pruebas.
Esta versión estabiliza la compatibilidad con las pruebas de Compose for Desktop. Jetpack Compose proporciona un conjunto de API de prueba para verificar el comportamiento del código Compose. Estas API se trasladaron anteriormente al escritorio y estaban disponibles en versiones anteriores con limitaciones. Estas limitaciones ahora se han eliminado, lo que le permite escribir pruebas de IU integrales para su aplicación.
Para demostrar rápidamente las capacidades de prueba, creemos y probemos una interfaz de usuario simple. A continuación se muestra nuestro ejemplo componible:
@Composable
fun App() {
var searchText by remember { mutableStateOf("cats") }
val searchHistory = remember { mutableStateListOf() }
Column(modifier = Modifier.padding(30.dp)) {
TextField(
modifier = Modifier.testTag("searchText"),
value = searchText,
onValueChange = {
searchText = it
}
)
Button(
modifier = Modifier.testTag("search"),
onClick = {
searchHistory.add("You searched for: $searchText")
}
) {
Text("Search")
}
LazyColumn {
items(searchHistory) {
Text(
text = it,
fontSize = 20.sp,
modifier = Modifier.padding(start = 10.dp).testTag("attempt")
)
}
}
}
}
Esto crea una interfaz de usuario simple que registra los intentos de búsqueda:
Tenga en cuenta que Modifier.testTag
se ha utilizado para dar nombres a las entradas en TextField
, Button
y LazyColumn
.
Luego podemos manipular la UI en una prueba JUnit:
class SearchAppTest {
@get:Rule
val compose = createComposeRule()
@Test
fun `Should display search attempts`() {
compose.setContent {
App()
}
val testSearches = listOf("cats", "dogs", "fish", "birds")
for (text in testSearches) {
compose.onNodeWithTag("searchText").performTextReplacement(text)
compose.onNodeWithTag("search").performClick()
}
val lastAttempt = compose
.onAllNodesWithTag("attempt")
.assertCountEquals(testSearches.size)
.onLast()
val expectedText = "You searched for: ${testSearches.last()}"
lastAttempt.assert(hasText(expectedText))
}
}
使用特定于 Compose 的 JUnit 规则:
将 UI 的内容设置为应用可组合项。
通过
onNodeWithTag
查找文本字段和按钮。在文本字段中重复输入示例值,然后点击按钮。
通过
onAllNodesWithTag
查找生成的所有文本节点。断言当前已创建的文本节点数,并获取最后一个。
断言最后一次尝试包含预期消息。
增强了 Swing 互操作性
此版本对 Swing 组件内 Compose 面板的改进呈现引入了实验性支持。这可以防止在显示、隐藏或调整面板大小时出现过渡呈现问题。它还支持在组合 Swing 组件和 Compose 面板时进行适当分层。Swing 组件现在可以在 ComposePanel
上方或下方显示。
为了说明这一点,请查看下面的示例:
fun main() {
System.setProperty("compose.swing.render.on.graphics", "true")
SwingUtilities.invokeLater {
val composePanel = ComposePanel().apply {
setContent {
Box(modifier = Modifier.background(Color.Black).fillMaxSize())
}
}
val popup = object : JComponent() { ... }
val rightPanel = JLayeredPane().apply {
add(composePanel)
add(popup)
...
}
val leftPanel = JPanel().apply { background = CYAN }
val splitter = JSplitPane(..., leftPanel,rightPanel)
JFrame().apply {
add(splitter)
setSize(600, 600)
isVisible = true
}
}
}
在这段代码中,我们创建并显示一个 Swing JFrame
,内容如下:
JFrame 包含带有垂直分隔线的
JSplitPane
。拆分窗格的左侧是青色的标准
JPanel
。右侧是
JLayeredPane
,由两层组成:包含
Box
可组合项的ComposePanel
,颜色为黑色自定义 Swing 组件,其中文本“Popup”出现在白色矩形内。这通过重写
paintComponent
方法实现。
属性 compose.swing.render.on.graphics
设为 true 时:
自定义 Swing 组件显示在
Box
可组合项顶部。移动滑块时不会出现过渡图形伪影。
如果此标志未设置,则自定义组件将不可见,并且滑块移动时可能出现过渡伪影:
请分享您对 Compose Multiplatform 的反馈。我们邀请您加入 Kotlin Slack #compose 频道,讨论与 Compose Multiplatform 和 Jetpack Compose 相关的一般主题。在 #compose-ios 中,您可以找到有关 Compose Multiplatform for iOS 的讨论。
试用 Compose Multiplatform 1.5.0:
https://github.com/JetBrains/compose-multiplatform/releases/tag/v1.5.0
更多文章和视频
使用 Compose Multiplatform 构建 iOS 和 Android 应用
https://www.youtube.com/watch?v=5_W5YKPShZ4
本博文英文原作者:
Kotlin 技术布道师
Garth Gilmour
这就是 Kotlin 编程语言
简洁、跨平台、且有趣!
本文分享自微信公众号 - JetBrains(JetBrainsChina)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。