Blog
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)

HiuZing

🍑
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)
  • 拉取安卓设备文件
  • permission
  • 常用命令
  • Android入门
  • Compose
    • 核心思想
    • setContent·
    • @Composable
    • @Preview
    • 常用组件
      • Text
      • Button
      • 图片 Image
      • Icon图标
      • Image和Icon和AsyncImage比较
      • 输入框 TextField
    • Modifier修饰符
    • 三大布局
      • Column垂直排列
      • Row水平排列
      • Box堆叠布局
      • Spacer间距
      • weight按比例分配
      • 完整入门页面
    • 状态管理和列表
      • 状态管理
      • 列表
      • Material3页面框架
      • Navigation
  • MVVM架构
  • 网络请求
  • 数据持久化
  • Android
HiuZing
2026-09-30
目录

Compose

@Composable、Modifier、三大布局(Column/Row/Box)、基础组件(Text/Image/Icon/ 网络图片)

# 核心思想

声明式 UI 框架

定义 State
↓
根据 State 描述 UI
↓
State 改变
↓
Compose 自动更新 UI
1
2
3
4
5
6
7

# setContent·

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            // Compose UI
            Text("Hello Android")
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11

执行流程

@ComposableMainActivity
↓
onCreate()
↓
setContent {}
↓
Compose UI
1
2
3
4
5
6
7

# @Composable

告诉 Compose:这个函数用于构建 UI。

@Composable
fun Greeting() {
    Text("Hello Android")
}
1
2
3
4

# @Preview

@Preview 是 Android Studio(AS)的实时预览注解——加上它之后,不需要把 App 跑到模拟器或真机上,就能在 AS 右侧的 Split/Design 面板里直接看到这个组件渲染出来的样子,写 UI 时可以边改边看,效率高很多。

@Preview(showBackground = true)  // showBackground 显示白色背景
@Composable
fun GreetingPreview() {
    MaterialTheme {
        Column(
            modifier = Modifier.padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            Text("第一行", fontSize = 20.sp, fontWeight = FontWeight.Bold)
            Text("第二行", fontSize = 16.sp, color = Color.Gray)
            Text("第三行", fontSize = 14.sp)
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 常用组件

# Text

Text(
    text = "Hello",
    fontSize = 20.sp,
    fontWeight = FontWeight.Bold
)
1
2
3
4
5

# Button

Button(
    onClick = {
        println("点击按钮")
    }
) {
    Text("点击")
}
1
2
3
4
5
6
7

# 图片 Image

ContentScale 效果 使用场景
Fit 保持原图比例,完整显示整张图,容器多余区域会留白 图标、产品预览图,需要图片全部可见
Crop 保持原图比例,把容器填满,超出容器的图片部分会被裁剪 头像、轮播 Banner、封面图
FillBounds 直接拉伸图片填满容器,不维持原图比例,图片可能变形 一般不推荐使用

本地图片

Image(
    painter = painterResource(
        id = R.drawable.logo // main/res/drawable/logo
    ),
    contentDescription = "Logo"
)
1
2
3
4
5
6

网络图片

Coil 是 Jetpack Compose 生态最流行的图片加载第三方库,支持网络图片、本地图片,自带缓存、占位图、错误图。

  1. 添加依赖(app/build.gradle.kts)

    dependencies {
        implementation("io.coil-kt:coil-compose:2.5.0")
    }
    
    1
    2
    3
  2. AsyncImage 基础使用代码

    AsyncImage(
        model = "https://xxx/test.jpg", // 图片url
        contentDescription = "网络图片",
        contentScale = ContentScale.Crop,
        placeholder = {
            // 加载中占位图
            Box(Modifier.background(Color.LightGray))
        },
        error = {
            // 加载失败展示图
            Box(Modifier.background(Color.Red))
        },
        modifier = Modifier.size(120.dp)
    )
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  3. SubcomposeAsyncImage精细控制

    import coil.compose.SubcomposeAsyncImage
    
    SubcomposeAsyncImage(
        model = "https://example.com/your-image.jpg",
        contentDescription = "图片描述",
        loading = {
            // 图片加载中占位:圆形进度条
            Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                CircularProgressIndicator()
            }
        },
        error = {
            // 加载失败占位:错误图标
            Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                Icon(Icons.Default.Error, contentDescription = null)
            }
        }
    )
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

# Icon图标

@Composable
fun IconDemo() {
    Row(
        modifier = Modifier.fillMaxWidth().padding(16.dp),
        horizontalArrangement = Arrangement.SpaceEvenly
    ) {
        // Material 预设图标
        Icon(
            imageVector = Icons.Default.Home,     // 首页图标矢量图
            contentDescription = "首页",           // 无障碍描述,读屏软件使用
            tint = Color.Black,                    // 图标着色
            modifier = Modifier.size(32.dp)        // 图标尺寸
        )

        // 搜索图标
        Icon(
            imageVector = Icons.Default.Search,
            contentDescription = "搜索",
            tint = Color(0xFF1A73E8), // 自定义十六进制颜色
            modifier = Modifier.size(32.dp)
        )

        // 爱心图标(截图中第三个)
        Icon(
            imageVector = Icons.Default.Favorite,
            contentDescription = "收藏",
            tint = Color(0xFF1A73E8),
            modifier = Modifier.size(32.dp)
        )
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
参数 作用
imageVector 矢量图标资源,Icons.Default.xxx,矢量图放大不会模糊
contentDescription 无障碍文本;不需要读屏时可以传 null
tint 图标颜色,矢量图标会被这个颜色染色
modifier 修饰符,常用 .size() 设置图标大小

# Image和Icon和AsyncImage比较

组件 用途 资源类型 特点
Image 展示本地图片 位图 PNG/JPG/WebP,painterResource(R.drawable.xxx) 放大容易模糊,不支持 tint 染色,适合照片、大图
Icon 展示矢量图标 Material 矢量图标 Icons.Default.xxx 矢量图,支持 tint 动态改色,放大不失真,适合小图标
AsyncImage(Coil) 加载网络图片 网络图片 URL 自带缓存、加载 / 错误占位,Coil 库提供

# 输入框 TextField

@Composable
fun InputDemo() {

    var name by remember {
        mutableStateOf("")
    }

    TextField(
        value = name,
        onValueChange = {
            name = it
        },
        label = {
            Text("请输入姓名")
        }
    )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# Modifier修饰符

设置尺寸、间距、背景、点击、位置等 UI 属性。

Text(
    text = "Hello",
    modifier = Modifier.padding(16.dp) // 四周增加 16dp 间距
)

// 链式调用
Modifier
    .fillMaxWidth()
    .height(50.dp)
    .padding(16.dp)

// 例子
Button(
    onClick = {},
    modifier = Modifier
        .fillMaxWidth()
        .padding(16.dp)
) {
    Text("登录")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

dp 和 sp

dp sp
宽度、高度、padding、margin 类似效果 字体大小
Text(
    text = "Hello",
    fontSize = 18.sp,
    modifier = Modifier.padding(16.dp)
)
1
2
3
4
5

Color

@Composable
fun ColorDemo() {
    Column(
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // 方式1:预设颜色
        Box(modifier = Modifier.size(60.dp).background(Color.Red))

        Spacer(modifier = Modifier.height(8.dp))

        // 方式2:ARGB 十六进制(最常用)
        // 0xFF=完全不透明,1A73E8=RGB色值
        Box(modifier = Modifier.size(60.dp).background(Color(0xFF1A73E8)))

        Spacer(modifier = Modifier.height(8.dp))

        // 方式3:带透明度
        Box(modifier = Modifier.size(60.dp).background(Color.Black.copy(alpha = 0.3f)))
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

常用 Modifier 速查表

Modifier
    // 尺寸
    .width(100.dp)        // 固定宽度
    .height(50.dp)        // 固定高度
    .size(48.dp)          // 宽高相同
    .fillMaxWidth()       // 填满父容器宽度
    .fillMaxSize()        // 填满父容器
    .weight(1f)           // 按比例分配空间(仅在 Row / Column 中)

    // 间距
    .padding(16.dp)                               // 四周内边距
    .padding(horizontal = 16.dp, vertical = 8.dp) // 分别设置水平、垂直内边距

    // 外观
    .background(Color.White)                     // 背景色
    .clip(RoundedCornerShape(8.dp))              // 圆角裁剪
    .border(1.dp, Color.Gray, RoundedCornerShape(8.dp)) // 边框

    // 交互
    .clickable { onClick() }                     // 点击事件

    // 其他
    .aspectRatio(2.65f)                          // 宽高比(宽:高 = 2.65:1)
    .offset(x = 10.dp, y = -4.dp)                // 偏移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

Modifier 从左到右依次应用

padding 在前,background 在后:padding 在背景外面,背景区域缩小。

background 在前,padding 在后:padding 在背景里面,背景铺满,内部留出空白。

例子(搜索框圆角)

// 先 clip 裁剪圆角,再绘制背景色,背景会跟着裁剪后的圆角形状显示。
Modifier.clip(RoundedCornerShape(8.dp)).background(Color.White)
1
2

# 三大布局

# Column垂直排列

Column {
    Text("第一行")
    Text("第二行") 
    Button(
        onClick = {}
    ) {
        Text("按钮")
    }
}
1
2
3
4
5
6
7
8
9

# Row水平排列

Row {
    Text("姓名:")
    Text("张三")
}
1
2
3
4

# Box堆叠布局

Box {
    Text("底层")
    Text("上层")
}
1
2
3
4

# Spacer间距

空白占位组件,专门用来做元素之间的间距,本身不会渲染任何内容。

@Composable
fun SpacerDemo() {
    Column(modifier = Modifier.padding(16.dp)) {
        Text("标题", fontSize = 20.sp, fontWeight = FontWeight.Bold)
        Spacer(modifier = Modifier.height(8.dp)) // 标题和内容之间 8dp 间距
        Text("这是内容文字", fontSize = 14.sp, color = Color.Gray)
    }
}
1
2
3
4
5
6
7
8

Spacervs spacedBy

Spacer 是空白占位组件,手动添加间距;spacedBy是布局参数,统一给所有子元素设置相同间距。推荐优先用 spacedBy 做统一间距;需要局部不同大小间距时,使用 Spacer。

# weight按比例分配

weight() 只能直接放在 Row / Column 的子元素上,用来瓜分容器剩余可用空间。

搭配 .fillMaxSize().子元素拿到分配到的空间后,fillMaxSize() 让 Box 填满分到的这块区域,色块才会完整显示。

// 比例 1:1:1 → 各占 1/3
Row(modifier = Modifier.fillMaxWidth().height(40.dp)) {
    Box(modifier = Modifier.weight(1f).fillMaxSize().background(Color.Red))
    Box(modifier = Modifier.weight(1f).fillMaxSize().background(Color.Green))
    Box(modifier = Modifier.weight(1f).fillMaxSize().background(Color.Blue))
}

Spacer(modifier = Modifier.height(8.dp))

// 比例 2:1 → 左边占 2/3,右边占 1/3
Row(modifier = Modifier.fillMaxWidth().height(40.dp)) {
    Box(modifier = Modifier.weight(2f).fillMaxSize().background(Color(0xFFFF9800)))
    Box(modifier = Modifier.weight(1f).fillMaxSize().background(Color(0xFF2196F3)))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 完整入门页面

@Composable
fun UserPage() {

    var count by remember {
        mutableStateOf(0)
    }

    Column(
        modifier = Modifier.padding(16.dp)
    ) {

        Text(
            text = "Compose 入门",
            fontSize = 24.sp
        )

        Text(
            text = "点击次数:$count"
        )

        Button(
            onClick = {
                count++
            }
        ) {
            Text("点击")
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 状态管理和列表

# 状态管理

@Composable
fun Counter() {

    var count by remember {
        mutableStateOf(0)
    }

    Button(
        onClick = {
            count++
        }
    ) {
        Text("点击次数:$count")
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# remember和mutableStateOf

API 作用
remember 记住值,界面重新绘制(重组)时不丢失
mutableStateOf 创建可观察的状态,值变化时自动刷新UI

by 是 Kotlin 的属性委托语法。

// 不使用 by
val count = remember { mutableStateOf(0) }

count.value++
Text("${count.value}")


// 使用 by
var count by remember { mutableStateOf(0) }

count++
Text("$count")
1
2
3
4
5
6
7
8
9
10
11
12

# 状态提升

类似 React 里的:

父组件 state
↓
props 传递
↓
子组件展示
↓
callback 修改父组件 state


@Composable
fun Parent(){

 var text by remember{
     mutableStateOf("")
 }

 SearchBox(
     text=text,
     onTextChange={
         text=it
     }
 )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 重组 Recomposition

状态改变,Compose 自动重新渲染受影响的界面。

// 流程

State 改变
↓
Compose 检测变化
↓
重新执行相关 Composable
↓
更新 UI
1
2
3
4
5
6
7
8
9

# 列表

# LazyColumn

Android Compose 中非常常见的列表组件

val names = listOf(
    "张三",
    "李四",
    "王五"
)

LazyColumn {
    items(names) { name ->
        Text(name)
    }
}
1
2
3
4
5
6
7
8
9
10
11
# 使用数据模型渲染列表

为什么不用普通 class?data class 自动生成方法;toString()、equals()、copy()

// 定义数据模型
data class QuestionItem(
    val id: String,
    val stem: String,
    val difficulty: Int,
    val views: Int
)

// 创建模拟数据
val mockQuestions = listOf(
    QuestionItem(
        "1",
        "Activity生命周期有哪些回调?",
        1,
        120
    ), 
    QuestionItem(
        "2",
        "Handler的底层原理是什么?",
        3,
        580
    ),
)

// 渲染
@Composable
fun QuestionList(){
    LazyColumn {
        items(mockQuestions){ question ->
            Column {
                Text(
                    text = question.stem
                )
                Text(
                    text = "难度:${question.difficulty}"
                )
                Text(
                    text = "浏览量:${question.views}"
                )
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 混合使用

item {} 和 items(list) {} 的区别

方法 作用 数量
item {} 单个固定内容 一个
items(list){} 循环列表数据 多个
LazyColumn {
    // 顶部轮播图
    item {
        BannerView()
    }

    // 分类 Tab
    item {
        CategoryTabs()
    }

    // 题目列表
    items(questionList) { question ->
        QuestionItem(question)
    }

    // 底部提示
    item {
        Text("没有更多数据")
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# LaunchedEffect

执行副作用 / 协程任务

LaunchedEffect(Unit) {

    println("页面进入")

}
1
2
3
4
5
key 值 行为 适用场景
Unit 只执行一次 进入页面时加载数据
某个变量 变量变化时重新执行 切换分类时重新加载
多个变量LaunchedEffect(key1, key2) 任意一个 key 变化,都会重新执行 分类 + 排序条件都变化时刷新

LaunchedEffect 内部启动了一个协程,里面可以直接调用:suspend 函数

LaunchedEffect(Unit) {

    delay(1000)

    println("1秒后执行")

}
1
2
3
4
5
6
7

例子2:根据 id 请求数据

@Composable
fun DetailPage(
    userId:Int
){

    // 仅执行一次
    LaunchedEffect(Unit) {
        loadPageData()
    }

    // userId变化就重新执行
    LaunchedEffect(userId) {
        getUser(userId)
    }

    // category 或 sort 任一变化就执行
    LaunchedEffect(category, sort) {
        loadData(category, sort)
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# rememberCoroutineScope

LaunchedEffect rememberCoroutineScope
启动方式 自动 手动
触发时机 Composable进入/Key变化 点击等事件
使用方式 直接写代码块 scope.launch
生命周期 Compose管理 Compose管理
常见场景 初始化请求 用户操作
// 页面加载
LaunchedEffect(Unit){
    viewModel.loadData()
}


// 点击刷新
// 获取协程作用域
val scope = rememberCoroutineScope() 

Button(
    onClick = {
        scope.launch {
            viewModel.refresh()
        }
    }
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# HorizontalPager

左右分页 / 轮播图

属性 / 方法 类型 作用 示例 使用场景
rememberPagerState State对象 保存 HorizontalPager 的状态 val pagerState = rememberPagerState() 管理轮播图、分页状态
pageCount Int 总页数(只读) pageCount = { banners.size } 告诉 Pager 有多少页
initialPage Int 初始显示第几页,默认 0 initialPage = 1 打开页面默认展示指定页
currentPage Int 当前正在显示的页面索引,从0开始 pagerState.currentPage 获取当前页码
targetPage Int 用户滑动时准备到达的页面 pagerState.targetPage 判断滑动目标
isScrollInProgress Boolean 当前是否正在滚动 pagerState.isScrollInProgress 控制加载动画、指示器显示

自动无线轮播完整版本

利用超大虚拟页数 Int.MAX_VALUE,从中间位置开始滑动; 通过取模运算 page % realCount,把巨大的 page 映射到真实数据下标,实现无限左右滑动的视觉效果。

@Composable
fun InfiniteBannerDemo() {
    // 真实轮播数据源
    val colors = listOf(
        Color(0xFFE91E63), // 粉色
        Color(0xFF2196F3), // 蓝色
        Color(0xFF4CAF50)  // 绿色
    )
    val realCount = colors.size
    if (realCount == 0) return

    // 虚拟页数:Int最大值,模拟无限
    val virtualCount = Int.MAX_VALUE
    // 起始页面放在中间,保证左右都能滑动很多页
    val startIndex = virtualCount / 2

    // 创建Pager状态
    val pagerState = rememberPagerState(
        initialPage = startIndex,
        pageCount = { virtualCount }
    )

    // 自动轮播:3秒自动翻页
    LaunchedEffect(pagerState) {
        while (true) {
            delay(3000.milliseconds)
            pagerState.animateScrollToPage(pagerState.currentPage + 1)
        }
    }

    // 当前真实下标,用于底部指示器
    val realIndex = pagerState.currentPage % realCount

    Box(modifier = Modifier.fillMaxSize()) {
        HorizontalPager(state = pagerState) { page ->
            // 核心:虚拟page对真实数量取模,拿到真实索引
            val index = page % realCount
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .background(colors[index]),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = "第${index + 1}页",
                    fontSize = 24.sp,
                    color = Color.White
                )
            }
        }

        // 底部圆点指示器
        Row(
            modifier = Modifier
                .align(Alignment.BottomCenter)
                .padding(bottom = 8.dp),
            horizontalArrangement = Arrangement.Center
        ) {
            repeat(realCount) { index ->
                Box(
                    modifier = Modifier
                        .size(8.dp)
                        .clip(RoundedCornerShape(4.dp))
                        .background(
                            if (realIndex == index) Color.White
                            else Color.White.copy(alpha = 0.5f)
                        )
                )
                Spacer(modifier = Modifier.width(4.dp))
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
代码 作用 关键点
virtualCount = Int.MAX_VALUE 虚拟总页数,制造无限滑动效果 并不是真的无限,只是数字极大,用户几乎滑不到边界
startIndex = virtualCount / 2 起始页面放在中间 保证向左、向右都可以滑动大量页面,不会很快到头
page % realCount 虚拟页码映射真实数据下标 写在 HorizontalPager 内部的 page 作用域,每个页面单独计算
realIndex = pagerState.currentPage % realCount 当前激活页真实索引 放在 Pager 外部,专门给底部指示器圆点判断选中状态
LaunchedEffect(pagerState) 自动轮播 while (true) 循环 + delay,3s 自动滚动到下一页;key 绑定 pagerState,页面销毁自动取消协程

# Material3页面框架

# Scaffold

顶部标题栏 页面内容 底部导航 悬浮按钮

Scaffold(
    topBar = {
        TopAppBar(
                title = { Text("面试通", fontWeight = FontWeight.Bold) },
                colors = TopAppBarDefaults.topAppBarColors(
                    containerColor = Color(0xFF1A73E8), // 背景色
                    titleContentColor = Color.White
                )
            )
    }
) { paddingValues ->

    Column(
        modifier = Modifier.padding(paddingValues)
    ) {
        Text("页面内容")
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# MaterialTheme

Compose 通常结合 Material Design 使用。

MaterialTheme {
    Text("Hello")
}
1
2
3

常见结构

setContent {
    MyApplicationTheme {
        MyPage()
    }
}
1
2
3
4
5

SecondaryScrollableTabRow 分类 Tab

ModalBottomSheet 底部弹窗

@Composable
fun FilterSheet(
    onDismiss:()->Unit
){

    var selectedSort by remember {
        mutableStateOf("默认")
    }
    ModalBottomSheet(
        onDismissRequest = onDismiss
    ){
        Column(
            modifier =
                Modifier
                    .padding(16.dp)
                    .height(300.dp)
        ){
            Row(
                modifier =
                    Modifier.fillMaxWidth(),
                verticalAlignment =
                    Alignment.CenterVertically
            ){

                Text(
                    "重置",
                    modifier =
                        Modifier.clickable {
                            selectedSort="默认"
                        }
                )
                Text(
                    "筛选题目",
                    fontWeight =
                        FontWeight.Bold
                )

            }
            Text(
                "当前排序:$selectedSort"
            )
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# Navigation

添加依赖

implementation(
    "androidx.navigation:navigation-compose" 
)
1
2
3

NavController + NavHost

NavController 负责控制页面跳转,NavHost 负责存放和展示页面。

@Composable
fun NavDemo() {
    // 创建并记住 NavController
    val navController = rememberNavController()
    // 监听当前页面变化,页面切换时自动更新
    val navBackStackEntry by navController.currentBackStackEntryAsState()
    // 当前页面的路由名
    val currentRoute = navBackStackEntry?.destination?.route

    NavHost(
        navController = navController,
        startDestination = Routes.HOME  // 启动后首先显示首页
    ) {
        // 注册页面(下一步实现)
        composable(
            Routes.LOGIN
            ){
                LoginScreen() 
                }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

携带参数跳转

@Composable
fun QuestionPage(
    navController: NavController,
    itemId: String?
) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(color = Color.Blue)
            .padding(top = 30.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text("问题详情页 ID=${itemId}", fontSize = 25.sp)
        Button(onClick = {
            navController.popBackStack()
        }) {
            Text("返回")
        }
    }
}

composable(Routes.QUESTION) { navBackStackEntry ->
    // 获取路由传递的参数
    val itemId = navBackStackEntry.arguments?.getString(key = "itemId")
    QuestionPage(navController, itemId)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
上次更新: 2026/10/07, 07:27:34
Android入门
MVVM架构

← Android入门 MVVM架构→

最近更新
01
02
数据持久化
10-06
03
网络请求
10-04
更多文章>
Theme by Vdoing | Copyright © 2021-2026 WeiXiaojing | 友情链接
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式