写了个简单的界面,包含功能:

1,列表中动态增加行和删除行

2,根据列表中的数据生成 json。

包含的文件或类:

1,Main.kt, 程序入口,使用 Window 即是 desktop 端。

2,View.kt, 画界面,只展示数据,没有业务逻辑。

3,ViewModel.kt,与View“绑定”,给View提供数据,及响应View接收到的用户操作。

4,Repository.kt,模拟读取数据库。

5,ViewStatus.kt,可以理解为元数据,状态。

效果:

程序很简单,不多说,直接贴代码

1,Main.kt

/*** 入口*/
fun main() = application {Window(state = WindowState(), onCloseRequest = ::exitApplication, title = "记录转 JSON") {App()}
}

2,View.kt

import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.VerticalScrollbar
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.rememberScrollbarAdapter
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp/*** 画界面*/private val viewModel: ViewModel = ViewModel()@Composable
@Preview
fun App() {val dataList: MutableList<Param> = remember { viewModel.viewState.paramList }val options: MutableList<Pair<String, Boolean>> = mutableListOf()options.add(Pair("是", true))options.add(Pair("否", false))//byLazyColumn(dataList, options)byScrollBar(dataList, options)
}/*** 使用 LazyColumn,不会显示滚动条*/
@Composable
fun byLazyColumn(list: MutableList<Param>, drops: MutableList<Pair<String, Boolean>>) {MaterialTheme {//dataList.add(Param("参数项描述", "参数值", 0))//dataList.add(Param("", "", 0))//val stateVertical = rememberScrollState(0)LazyColumn(verticalArrangement = Arrangement.spacedBy(5.dp) // 行间距) {item {renderHead()}itemsIndexed(list) { idx, item ->renderItem(item, list, idx, drops)}item {renderTail()}}}
}/*** 有滚动条*/
@Composable
fun byScrollBar(list: MutableList<Param>, drops: MutableList<Pair<String, Boolean>>) {Column {renderHead()Row {Box(//必须要包在 Box 里面,滚动条才会显示出来modifier = Modifier.height(400.dp).fillMaxWidth()//.background(color = Color(180, 180, 180)).padding(10.dp)) {val stateVertical = rememberScrollState(0)Column(modifier = Modifier.height(400.dp).verticalScroll(stateVertical).fillMaxWidth().padding(end = 12.dp, bottom = 12.dp)) {list.forEachIndexed { idx, item ->renderItem(item, list, idx, drops)}}VerticalScrollbar(modifier = Modifier.align(Alignment.CenterEnd),adapter = rememberScrollbarAdapter(stateVertical))}}renderTail()}
}/*** 画一行*/
@Composable
fun renderItem(item: Param, list: MutableList<Param>, index: Int, drops: MutableList<Pair<String, Boolean>>) {val content = remember { mutableStateOf(item.content) }val isdtc = remember { mutableStateOf(item.isdtc) }val value = remember { mutableStateOf(TextFieldValue(if (item.value == null) "" else item.value.toString())) }Row {OutlinedTextField(value = content.value,modifier = Modifier.padding(horizontal = 20.dp).width(150.dp),onValueChange = {item.content = itcontent.value = it})OutlinedTextField(value = value.value,modifier = Modifier.padding(horizontal = 20.dp).width(150.dp),onValueChange = {try {item.value = it.text.toInt()value.value = it} catch (e: Exception) {item.value = nullvalue.value = TextFieldValue("")}})drops.forEach { option ->Row(Modifier.width(95.dp),verticalAlignment = Alignment.CenterVertically) {RadioButton(//    通过观察对象和index相同判断是否被选中selected = (isdtc.value == option.second),//    点击事件onClick = {isdtc.value = option.seconditem.isdtc = option.second})Text(text = option.first)}}//        DropdownMenu(expanded = true, modifier = Modifier.padding(horizontal = 20.dp).width(150.dp), onDismissRequest = {}) {
//            drops.forEach {
//                DropdownMenuItem(onClick = {
//                    item.value = it.second
//                }) {
//                    Text(text = it.first)
//                }
//            }
//        }if (index == list.size - 1) {Button(modifier = Modifier.padding(horizontal = 20.dp), onClick = {//list.removeAt(index)val removeItemAction = ViewAction.RemoveItemAction()removeItemAction.target = itemviewModel.dispatch(removeItemAction)}) {Text("删除")}}}
}/*** 表头*/
@Composable
fun renderHead() {Row(horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) {Text(text = "参数项描述",modifier = Modifier.padding(horizontal = 20.dp).width(150.dp),textAlign = TextAlign.Center)Text(text = "参数值",modifier = Modifier.padding(horizontal = 20.dp).width(150.dp),textAlign = TextAlign.Center)Text(text = "是否故障",modifier = Modifier.padding(horizontal = 20.dp).width(150.dp),textAlign = TextAlign.Center)Button(modifier = Modifier.padding(horizontal = 20.dp), onClick = {//list.add(Param("", null, false))viewModel.dispatch(ViewAction.AddItemAction)}) {Text("增加")}}
}/*** 底部的按钮“生成json”和大文本框*/
@Composable
fun renderTail() {Row(horizontalArrangement = Arrangement.Center) {val state = remember {viewModel.viewState.result}Button(modifier = Modifier.padding(horizontal = 20.dp), onClick = {viewModel.dispatch(ViewAction.GenerateJsonAction)}) {Text("生成 JSON")}OutlinedTextField(value = state.value,onValueChange = { text -> state.value = text },modifier = Modifier.width(500.dp))}
}

3,ViewModel.kt

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.toMutableStateListclass ViewModel {private val repository = Repository()val viewState: ViewState = ViewState(repository.query().toMutableStateList(), mutableStateOf(""))private fun generateJson() {val json = StringBuilder("[")viewState.paramList.forEach {if (it.content.isNotEmpty()) {json.append("$it,")}}if (json.endsWith(",")) {json.delete(json.length - 1, json.length)}json.append("]")viewState.result.value = json.toString()}private fun addItem() {viewState.paramList.add(Param("", null, false))}private fun removeItem(item: Param?) {if (item != null) {viewState.paramList.remove(item)}}fun dispatch(action: ViewAction) {when(action) {ViewAction.GenerateJsonAction -> generateJson()ViewAction.AddItemAction -> addItem()else ->if (action is ViewAction.RemoveItemAction) {removeItem(action.target)}}}
}

4,Repository.kt

/*** 管理数据,或者处理业务逻辑*/
class Repository {fun query(): MutableList<Param>{val list: MutableList<Param> = mutableListOf()list.add(Param("", null, false))return list}
}

5,ViewStatus.kt

import androidx.compose.runtime.MutableState/*** 界面上的数据:一个列表,及根据列表生成的 json*/
data class ViewState(val paramList: MutableList<Param>, var result: MutableState<String>)/*** 界面上的操作定义*/
sealed class ViewAction {/** 增加一行 */object AddItemAction: ViewAction()/** 生成 json */object GenerateJsonAction: ViewAction()/** 删除一行 */class RemoveItemAction: ViewAction() {var target: Param? = null}
}/*** 列表中显示的数据类型*/
data class Param(var content: String, var value: Int?, var isdtc: Boolean) {override fun toString(): String {return if (value != null) "{\"content\":\"$content\", \"value\":$value, \"isdtc\":\"$isdtc\"}"else "{\"content\":\"$content\", \"isdtc\":\"$isdtc\"}"}
}

Compose Multiplatform结合MVI模式--初步尝试相关推荐

  1. Compose也能跨平台?Compose Multiplatform是啥?KMM又是什么?

    现在的跨平台框架真是跟打了鸡血似的,跟生产队的驴一样玩命的更新啊,一会儿功夫就遍地开花,开发者尤其是Androiders们还能学得过来吗? Compose Multiplatform Compose ...

  2. 10个问题带你看懂 Compose Multiplatform 1.0

    近日 JetBrains 正式发布了 Compose Multiplatform 1.0 版,这标志其在生产环境中使用的时机已经成熟.相信有不少人对它还不太熟悉,本文通过下面 10 个热门问题带大家认 ...

  3. Compose Multiplatform 正式官宣,与 Flutter 必有一战?

    作者 | fundroid 来源 | AndroidPub 7月底 Compose for Android 1.0 刚刚发布,紧接着 8月4日 JetBrains 就宣布了 Compose Multi ...

  4. Compose Multiplatform 正式官宣,与 Flutter 迟早必有一战?

    7月底 Compose for Android 1.0 刚刚发布,紧接着 8月4日 JetBrains 就宣布了 Compose Multiplatform 的最新进展,目前已进入 alpha 阶段. ...

  5. 腾讯SkillNet|NLU任务全能网络,对Pathways架构的初步尝试

    卷友们好,我是rumor. 21年10月的时候,谷歌大佬Jeff Dean提出了下一代AI架构的Pathways概念[1],旨在通过一个大模型完成各种不同的任务.对于较早关注AI领域的同行们来说,这其 ...

  6. Compose Multiplatform 实战:联机五子棋

    1. 认识 Compose Multiplatform Jetpack Compose 作为 Android 端的新一代UI开发工具,得益于 Kotlin 优秀的语法特性,代码写起来十分简洁,广受开发 ...

  7. 又一款跨平台开发框架 :Compose Multiplatform 1.0 发布!

    点击"开发者技术前线",选择"星标" 让一部分开发者看到未来 作者 | 罗燕珊   来自 infoQ JetBrains 工程师 Sebastian Aigne ...

  8. 使用Compose实现基于MVI架构、retrofit2、支持 glance 小部件的TODO应用

    前言 现在声明式 UI 已逐渐成为主流,在客户端上,已有成熟的 Flutter 和 SwiftUi ,而原生安卓上的声明式 UI 却在去年年底才姗姗来迟. 虽然 compose 姗姗来迟,但是关于它的 ...

  9. 4.2 手机模拟操作初步尝试(获取登录页面的源代码)

    本节先来初步尝试手机模拟操作,为之后爬取微信朋友圈的实战演练做铺垫. 4.2.1 用Android Studio 连接夜神模拟器 要操控手机App,得先连接到手机.前面安装的夜神模拟器就是用来模拟An ...

最新文章

  1. 常州大学阿里云大数据学院举行“创新思维”课程答辩
  2. Android 5.0 SEAndroid下如何获得对一个内核节点的访问权限
  3. tableau应用实战案例(五十)-销售业绩的tableau可视化案例
  4. BugKuCTF WEB 本地包含
  5. 命令行切换到conda环境_Anaconda命令行常用操作
  6. 事实表和维度表是怎么造数据_从电商数据指标到电商数据中台
  7. 关于没有commit的死锁问题
  8. 工作中JS语法的小整理以及vue小知识的收纳
  9. 《python自动化》学习笔记:正则表达式基础知识
  10. HyperLogLog浅析
  11. 小程序解析短视频接口API开发文档
  12. 500个运营工具大全,速度收藏!!!
  13. Symbian 项目
  14. 机器学习笔记之概率图模型(五)马尔可夫随机场的结构表示
  15. fw313r路由器上网方式服务器无响应,迅捷(FAST)路由器fw313r手机设置上网方法
  16. python神经网络图像分类,图像分类卷积神经网络
  17. 智能温室监测系统解决方案
  18. 安装完固态硬盘后计算机里没显示,如何解决安装固态硬盘后系统看不到的问题[详细介绍]...
  19. 理解OAuth 2.0
  20. C语言为什么不执行数组下标的有效性检查

热门文章

  1. 【Excel设置任意列为默认文本格式】
  2. vi/vim简介及使用教程
  3. linux7网口起不来,centos7 双网口绑定
  4. 大白映射 宝马Esys编程设码映射、USB设备映射
  5. 2021第六届天梯赛cccc总决赛题解
  6. 物联网安全的发展现状与展望
  7. 设备常用网管配置举例
  8. 鼓励员工离婚,宣布996的有赞还能走多久?
  9. 每个人都能制作的简易版QQ音乐(HTML+CSS+JQuery)
  10. useRoutes与React.lazy的使用