二、Kotlin高级特性以及Compose状态驱动UI

二、Kotlin高级特性以及Compose状态驱动UI

在昨天的基础上,学习Kotlin的高级特性(扩展函数和作用域函数)

并且了解Compose状态管理

1、Kotlin高级特性

  • 扩展函数与扩展属性

    • 无需继承,Kotlin就可以给现有类添加方法,并可以直接调用(添加之后整个项目中都可以使用)

    kotlin 复制代码
    //给String类添加验证邮箱的方法
    fun String.isValidEmail(): Boolean {
        return this.contains("@") && this.contains(".")
    }
    
    //在其他类中可以直接使用
    "xxx@163.com.com".isValidEmail() // true
    • 扩展属性同理

    kotlin 复制代码
    val Note.type: Int
    	get() = 1
    
    
    //注意,如果添加的扩展属性原类中已存在,则不会生效。
  • 作用域函数

    • 用于简化对象操作,常用的作用域函数有:let,apply,run,also,with

    • let:常用于空安全操作、转换、作用域隔离等,返回最后一行代码值,上下文使用it引用

      kotlin 复制代码
      val name2: String? = "Marry"
      
      name2?.let {
          print("Hello,$it")
          it.length //返回的字符串长度
      }
      
      //链式转换
      val toPrint = name2?.let { it.uppercase() } ?.let { "Hi,$it" }
      //toPrint结果为:Hi,MARRY
    • run:常用于初始化并返回计算结果,上下文使用this引用

      kotlin 复制代码
      val noteEX = Note(1L, title = "测试笔记", content = "我是内容", timestamp = "2026-01-07")
      
      val printStr = noteEX.run {
          "${this.title}(${this.timestamp}):${this.content}"
      }
      //返回值为:测试笔记(2026-01-07):我是内容
    • apply:配置对象并返回自身,上下文使用this引用

      kotlin 复制代码
      data class Parson(
          var name: String,
          var age: Int
      )
      
      val parson = Parson(name = "susan", age = 18)
      
      val newParson = parson.apply {
          this.age = 20//这里age一定是用var定义的,如果是val定义的是不可变的,会报错
      }
    • also:执行副作用并返回自身,上下文使用it引用

      kotlin 复制代码
      val parson = Parson(name = "susan", age = 18)
      
      parson.also{
          Log.d("Parson","Parson name : ${it.name}")
      }
    • with:对现有对象执行多步操作(非扩展函数,是普通函数!),上下文使用this引用

      kotlin 复制代码
      val anote = Note()
      val a = with(anote) {
          this.title
          this.content
      }
      
      //这里返回值为content

      with返回值是最后一行结果

  • 数据类增强

    • 我们在(昨天的Note)数据类中新增一个标签字段

    kotlin 复制代码
    val tags: List<String> = emptyList() // 新增标签字段

    emptyList() 是不可变空列表,安全高效

    • 数据类可以使用copy()方法创建新实例,用于状态更新:

    kotlin 复制代码
    val updatedNote = originalNote.copy(title = "新标题")
  • 委托

    • 使用by进行属性委托

    kotlin 复制代码
    interface Base {
        fun print()
    }
    
    class BaseImpl(val x: Int) : Base {
        override fun print() = println(x)
    }
    
    // 使用 by 委托:Derived 将 Base 接口的实现委托给 baseObject
    class Derived(baseObject: Base) : Base by baseObject

2、Jetpack Compose状态管理

  • 什么是状态(State)
    • 状态是 驱动 UI 变化的数据
    • 当状态改变 → Compose 自动 重组(Recompose) 相关 UI
    • 比如旧的android中控制组件隐藏显示通过控制**visibility** 值来实现,而使用状态管理之后则可以使用一个自定义的状态值来控制,值为true显示,false隐藏,具体逻辑是可控的。
  • mutableStateOf+by委托
    • mutableStateOf(false):创建一个可变状态容器
    • by:使用属性委托,让 expanded 行为像普通变量
    • remember:在重组时保持状态值(避免每次重建为 false)
    • 注意mutableStateOf(false)方法使用时不要用错了,有很多类似的方法,用来做不同的状态管理。
  • 状态提升(State Hoisting)原则
    • 状态应定义在 需要控制它的最高共同父组件
    • 今日暂不提升(状态在 NoteCard 内部),后续会移到 ViewModel

3、完整的项目代码升级

  • 更新Note.kt文件,新增tags字段用来保存标签的tag信息。

    kotlin 复制代码
    // Note.kt
    data class Note(
        val id: Long = 0L,
        val title: String = "",
        val content: String = "",
        val timestamp: String = "",
        val tags: List<String> = emptyList() // ← 新增
    )
  • 更新NoteCard.kt,新增标签展示和支持通过状态进行页面组件管理。

    kotlin 复制代码
    package com.jiahengfei.ktdm
    
    import android.widget.Toast
    import androidx.compose.foundation.clickable
    import androidx.compose.foundation.layout.Arrangement
    import androidx.compose.foundation.layout.Column
    import androidx.compose.foundation.layout.Row
    import androidx.compose.foundation.layout.Spacer
    import androidx.compose.foundation.layout.fillMaxWidth
    import androidx.compose.foundation.layout.height
    import androidx.compose.foundation.layout.padding
    import androidx.compose.foundation.lazy.staggeredgrid.rememberLazyStaggeredGridState
    import androidx.compose.material3.Button
    import androidx.compose.material3.Card
    import androidx.compose.material3.CardDefaults
    import androidx.compose.material3.MaterialTheme
    import androidx.compose.material3.OutlinedButton
    import androidx.compose.material3.Scaffold
    import androidx.compose.material3.SnackbarHost
    import androidx.compose.material3.SnackbarHostState
    import androidx.compose.material3.Text
    import androidx.compose.runtime.Composable
    import androidx.compose.runtime.getValue
    import androidx.compose.runtime.mutableStateOf
    import androidx.compose.runtime.remember
    import androidx.compose.runtime.rememberCoroutineScope
    import androidx.compose.runtime.setValue
    import androidx.compose.ui.Alignment
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.graphics.Color
    import androidx.compose.ui.unit.dp
    import kotlinx.coroutines.launch
    
    /**
     * Create by zFox from AndroidStudio2022.01
     * 日期:2026/1/5 20:01
     * 描述:UI组件
     */
    
    @Composable
    fun NoteCard(
        note: Note,
        showSnackBar: (String) -> Unit,
        modifier: Modifier = Modifier
    ) {
        //状态声明
        var expanded by remember { mutableStateOf(false) }
    
        Card(
            modifier = modifier
                .padding(8.dp)
                .fillMaxWidth()
                .clickable {
                    showSnackBar("点击了卡片${note.id}")
                },
            elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
            colors = CardDefaults.cardColors(containerColor = Color.White)
        ) {
    
            Column(
                modifier = Modifier
                    .padding(16.dp)
                    .fillMaxWidth(),
                verticalArrangement = Arrangement.Top
            ) {
                Text(
                    text = note.title,
                    style = MaterialTheme.typography.headlineSmall
                )
    
                Spacer(modifier = Modifier.height(8.dp))
                Text(
                    text = note.content,
                    style = MaterialTheme.typography.bodyMedium
                )
    
                if (expanded) {
                    if (note.tags.isNotEmpty()) {
                        Spacer(modifier = Modifier.height(8.dp))
                        Row(
                            horizontalArrangement = Arrangement.spacedBy(4.dp),
                            verticalAlignment = Alignment.CenterVertically
                        ) {
                            note.tags.forEach { tag ->
                                OutlinedButton(
                                    onClick = {
                                    },
                                    shape = MaterialTheme.shapes.small,
                                    modifier = Modifier.height(32.dp)
                                ) {
                                    Text(
                                        text = "#$tag",
                                        style = MaterialTheme.typography.labelSmall
                                    )
                                }
                            }
                        }
                    }
                }
    
                Spacer(modifier = Modifier.height(8.dp))
                Text(
                    text = note.timestamp,
                    style = MaterialTheme.typography.labelSmall,
                    color = MaterialTheme.colorScheme.outline
                )
    
                //展开-收起按钮
                Spacer(modifier = Modifier.height(12.dp))
    
                if (note.tags.isNotEmpty()) {
                    Button(
                        onClick = {
                            expanded = !expanded
                        },
                        modifier = Modifier
                            .align(Alignment.End)
                            .height(32.dp)
                    ) {
                        Text(
                            if (expanded) "收起Tags" else "展开Tags",
                            style = MaterialTheme.typography.labelSmall,
                        )
                    }
                }
            }
        }
    }
  • 更新MainActivity.kt,传入带标签的笔记,以及提供给子组件一个显示Snackbar的方法

    kotlin 复制代码
    setContent {
        NoteAppTheme() {
            val snackBarHostState = remember { SnackbarHostState() }
            val scope = rememberCoroutineScope()
    
    
    
            Scaffold(
                snackbarHost = { SnackbarHost(snackBarHostState) }
            ) {
                Surface(
                    modifier = Modifier
                        .fillMaxWidth()
                        .systemBarsPadding(),
                    color = MaterialTheme.colorScheme.background,
                ) {
                    Column(
                        modifier = Modifier
                            .fillMaxWidth()
                    ) {
                        val showMsg = { msg: String ->
                            scope.launch {
                                snackBarHostState.showSnackbar(msg)
                            }
                            Unit
                        }
    
                        val sampleNote = Note(
                            1L,
                            "第一天学习笔记",
                            "今天非常之Nice!",
                            "2026-01-05",
                        )
                        NoteCard(sampleNote, showMsg)
    
                        val sampleNote2 = Note(
                            2L,
                            "第二天学习笔记",
                            "今天学习了 Kotlin 扩展函数和 Compose 状态管理,实现了可交互的笔记卡片!",
                            "2026-01-06",
                            listOf("Kotlin", "Compose", "Android")
                        )
                        NoteCard(sampleNote2, showMsg)
                    }
                }
            }
        }
    }
查看运行效果:

第二天的学习就到这里吧!明日见~

相关推荐
console.log('npc')5 小时前
响应式布局的 Element UI、Ant Design 24栅格布局
vue.js·ui
田里的水稻5 小时前
EI_openclaw_UI交互
人工智能·ui·机器人
NGBQ121387 小时前
Adobe-Photoshop-2026-27.4.0.15-m0nkrus 全解析:专业图片处理软件深度指南
ui·adobe·photoshop
stevenzqzq9 小时前
MVI架构3--实战示例:我的收藏页面
设计规范·compose·mvi架构
mxwin9 小时前
Unity Shader UI 流光效果完全推导指南
ui·unity·游戏引擎·shader·uv
程序员Ctrl喵10 小时前
UI 构建系统 —— “万物皆 Widget”的哲学
ui
Yang-Never11 小时前
OpenGL ES ->YUV图像基础知识
android·java·开发语言·kotlin·android studio
我的offer在哪里11 小时前
腾讯 Ardot 深度博客:AI 重构 UI/UX 全链路,从 “描述即界面” 到设计工业化的腾讯范式
人工智能·ui·重构
idealzouhu12 小时前
【Kotlin】 数据流完全指南:冷流、热流与 Android 实战
android·开发语言·kotlin
常利兵12 小时前
Android 字体字重设置:从XML到Kotlin的奇妙之旅
android·xml·kotlin