Compose跨平台第一弹:体验Compose for Desktop

news/2024/11/8 13:35:19/

前言

Compose是Android官方提供的声明式UI开发框架,而Compose Multiplatform是由JetBrains 维护的,对于Android开发来说,个人认为学习Jetpack Compose是必须的,因为它会成为Android主流的开发模式,而compose-jb作为一个扩展能力,我们可以有选择的去尝试。今天我们先来了解一下使用compose-jb开发一个桌面端应用的流程。

接下来还会有第二弹,第三弹...

环境要求

开发Compose for Desktop环境要求主要有两点:

  • JDK 11或更高版本

  • IntelliJ IDEA 2020.3 或更高版本(也可以使用AS,这里为了使用IDEA提供的项目模板)

接着我们来一步步体验Compose for Desktop的开发流程。

开发流程

创建项目

下载好IDEA后,我们直接新建项目,选择Compose Multipalteform类型,输入项目名称,这里只选择Single platform且平台为Desktop即可。

 创建好项目后,来看项目目录结构,目录结构如下图所示。

 

在配置文件中指定了程序入口为MainKt以及包名、版本号等。MainKt文件代码如下所示。

@Composable
@Preview
fun App() {var text by remember { mutableStateOf("Hello, World!") }MaterialTheme {Button(onClick = {text = "Hello, Desktop!"}) {Text(text)}}
}fun main() = application {Window(onCloseRequest = ::exitApplication) {App()}
}

在MainKt文件中,入口处调用了App()方法,App方法中绘制了一个按钮,运行程序,结果如下图所示。

我们可以看到一个Hello World的桌面端程序就显示出来了。接下来我们来添加一些页面元素。

添加输入框

为了让桌面端程序更“像样子”,我们首先修改桌面程序的标题为“学生管理系统”,这毕竟是我们学生时代最喜欢的名字。代码如下所示:

fun main() = application {Window(onCloseRequest = ::exitApplication, title = "学生管理系统") {App()}
}

在App方法中,添加两个输入框分别为学号、密码,添加一个登陆按钮,写法与Android中的Compose一致,代码如下所示。

MaterialTheme {var name by remember {mutableStateOf("")}var password by remember {mutableStateOf("")}Column {TextField(name, onValueChange = {name = it}, placeholder = {Text("请输入学号")})TextField(password, onValueChange = {password = it}, placeholder = {Text("请输入密码")})Button(onClick = {}) {Text("登陆")}}}

再次运行程序,页面如下所示。

 

添加头像

接着我们再来添加头像显示,我们将下载好的图片资源放在resources目录下

然后使用Image组件将头像显示出来即可,代码如下所示。

Image(painter = painterResource("photo.png"),contentDescription = null,modifier = Modifier.size(width = 100.dp, height = 100.dp).clip(CircleShape)
)

再次运行程序,结果如下所示。

 

当然我们还可以将布局稍微修饰一下,使得布局看起来更好看一些。但这并不是这里的重点。

添加退出弹窗

当我们点击左上角(macOS)的X号时,应用程序就直接退出了,这是因为在Window函数中指定了退出事件,再来看一下这部分代码,如下所示。

fun main() = application {Window(onCloseRequest = ::exitApplication, title = "学生管理系统") {App()}
}

接下来我们增加一个确认退出的弹窗提醒。代码如下所示。

fun main() = application {var windowsOpen by remember {mutableStateOf(true)}var isClose by remember {mutableStateOf(false)}if (windowsOpen) {Window(onCloseRequest = { isClose = true }, title = "学生管理系统") {App()if (isClose) {Dialog(onCloseRequest = { isClose = false }, title = "确定退出应用程序吗?") {Row {Button(onClick = {windowsOpen = false}) {Text("确定")}}}}}}}

这里我们新增了两个变量windowsOpen、isClose分别用来控制应用程序的Window是否显示与确认弹窗的显示。这部分代码相信使用过Jetpack Compose的都可以看得懂。

运行程序,点击X号,弹出退出确认弹窗,点击确定,应用程序将退出。效果如下图所示。

 

实现一个网络请求功能

在 Kotlin 跨平台开发入门 中我们借用「wanandroid」中「每日一问」接口实现了一个网络请求,现在我们将这部分功能移植到Desktop程序中,网络请求框架仍然使用Ktor,当然其实你也可以使用Retrofit,这一点并不重要。

首先添加Ktor的依赖,代码如下所示。

val jvmMain by getting {dependencies {implementation(compose.desktop.currentOs)implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")val ktorVersion = "2.1.2"implementation("io.ktor:ktor-client-core:$ktorVersion")implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")implementation("io.ktor:ktor-client-android:$ktorVersion")}
}

添加一个Api接口

object Api {val dataApi = "https://wanandroid.com/wenda/list/1/json"
}

创建HttpUtil类,用于创建HttpClient对象和获取数据的方法,代码如下所示。

import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Jsonclass HttpUtil {private val httpClient = HttpClient {install(ContentNegotiation) {json(Json {prettyPrint = trueisLenient = trueignoreUnknownKeys = true})}}/*** 获取数据*/suspend fun getData(): String {val rockets: DemoReqData =httpClient.get(Api.dataApi).body()return "${rockets.data} "}
}

DemoReqData是接口返回数据对应映射的实体类,这里就不再给出了。

然后我们编写UI,点击按钮开始网络请求,代码如下所示。

Column() {val scope = rememberCoroutineScope()var demoReqData by remember { mutableStateOf(DemoReqData()) }Button(onClick = {scope.launch {try {demoReqData = HttpUtil().getData()} catch (e: Exception) {}}}) {Text(text = "请求数据")}LazyColumn {repeat(demoReqData.data?.datas?.size ?: 0) {item {Message(demoReqData.data?.datas?.get(it))}}}
}

获取数据后,通过Message方法将数据展示出来,这里只将作者与标题内容显示出来,代码如下所示。

@Composable
fun Message(data: DemoReqData.DataBean.DatasBean?) {Card(modifier = Modifier.background(Color.White).padding(10.dp).fillMaxWidth(), elevation = 10.dp) {Column(modifier = Modifier.padding(10.dp)) {Text(text = "作者:${data?.author}")Text(text = "${data?.title}")}}
}

运行程序,点击“请求数据”,结果如下图所示。

 

这样我们就实现了一个简单的桌面端数据请求与显示功能。

写在最后

当然,在Compose For Desktop中还有许多的组件,比如Tooltips、Context Menu等等,这里无法一一介绍,需要我们在使用的时候去实践,我们将在后面的N弹中持续探索...


http://www.ppmy.cn/news/9902.html

相关文章

寒假本科创新——机器学习(二)

绪论1.3归纳偏好 一般原则:奥卡姆剃刀 什么样的算法比较好?1.4NFL定理 NFL定理的前提: NFL定理的寓意:1.3归纳偏好 归纳偏好(lnductive Bias): 机器学习算法在学习过程中对某种类型假设的偏好…

JAVA并发编程工具篇--1.1理解Future获取线程执行结果

背景:在并发编程中,我们可以使用Future来获取子线程执行的结果,然后在主线程一起进行业务处理; 那么Future是如何来工作的; 1 使用: demo1:使用Future每次都阻塞获取任务的执行结果&#xff1a…

android 换肤框架搭建及使用 (3 完结篇)

本系列计划3篇: Android 换肤之资源(Resources)加载(一)setContentView() / LayoutInflater源码分析(二)换肤框架搭建(三) — 本篇 tips: 本篇只说实现思路,以及使用,具体细节请下载代码查看! 本篇实现效果: fragment换肤recyclerView换肤自定义view属性换肤打开打开打开动…

Java Bean Validation

JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面,就可以在需要校验的时候进行校验了。校验框架注解如下: 注解解释Null被注释的元素必须为nullNotNull被注释…

成为有钱人的终极秘诀:做到这7步,你也可以成为富人!

经常有人问:互联网有什么快速赚钱的方法?大多数人内心浮躁,总想以最快的方式搞到钱。因为浮躁,所以沉不下心来去搞钱。做一个项目赚不到钱,然后又开始找项目,换项目,做项目,一直恶性循环中。最…

whistle的使用【前端抓包】

前言 抓包工具看起来只是测试要用的东西,其实对前端作用也很多,因为我们也要模拟请求、mock数据、调试。站在巨人肩膀上永远不亏! whistle能解决的痛点 一、看请求不方便 跳页、支付时候上一页的请求结果看不到,h5、小程序newWork不能在电…

SQL用法详解

1.SQL语言是什么?有什么作用?SQL:结构化查询语言,用于操作数据库,通用于绝大多数的数据库软件2.SQL的特征大小写不敏感需以;号结尾支持单行、多行注释3操作数据库的SQL语言基于功能可以划分为4类:数据定义:DDL ( Data Definition Language)&#xff1a…

GO——函数(一)

函数函数声明多返回值错误错误处理策略文件结尾错误(EOF)函数值函数声明 函数声明包括函数名、形式参数列表、返回值列表(可省略)以及函数体。 func name(parameter-list) (result-list) {body }返回值也可以像形式参数一样被命名。在这种情况下&#…