Greeting Card
朋友vibe了一个安卓端的Quiz APP,于是对安卓开发有点兴趣。找到Google官网的入门教程,学习了最简单的项目写法。以下做简要记录,以便复习。
IDE
Android Studio Quail 2 | 2026.1.2
注意点:
访问 dl.google.com 需要改host文件
gradle 更新和换镜像源
MainActivity.kt
主函数 MainActivity.kt 有两个关键组成:onCreate() 和 setContent()。
onCreate()
Explain
The `onCreate()` function is the entry point to this Android app and calls other functions to build the user interface. In Kotlin programs, the `main()` function is the entry point/starting point of execution. In Android apps, the `onCreate()` function fills that role.函数功能:作为整个App的入口,相当于Kotlin程序中的 main()函数。
setContent()
Explain
The setContent() function within the `onCreate()` function is used to define your layout through composable functions. All functions marked with the `@Composable` annotation can be called from the `setContent()` function or from other Composable functions. The annotation tells the Kotlin compiler that this function is used by **Jetpack Compose** to generate the UI.函数功能:为该 View 设置 Jetpack Compose 的UI内容。
懒加载机制(Lazy execution):当调用 setContent()时,Compose 并不会立刻去渲染和执行里面的代码。它会把你的代码先存起来,等到合适的时机再真正执行。时机有两个:
- 这个
ComposeView被系统加载,也就是该 View 附加到窗口上时 - 主动调用
createComposition(),代码会提前加载
Template
旧:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
GreetingCardTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = Color(0xFF6200EE) // 亮紫色
) {
Greeting("Android")
}
}
}
}
}
新:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge() // change1: 新增EdgeToEdge支持
setContent {
GreetingCardTheme {
Scaffold( // change2: 使用Scaffold取代Surface
modifier = Modifier.fillMaxSize(),
containerColor = Color(0xFF6200EE) // 亮紫色
) { innerPadding ->
Greeting(
name = "Alice",
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
}
新旧示例对比
旧:Surface Container
新:Edge-to-Edge + Scaffold Container
对不同组合的效果进行实验,对比图如下:
enableEdgeToEdge() |
Container |
颜色 | 内容 |
|---|---|---|---|
| 不开启 | Surface |
状态栏亮,内容暗 | 与状态栏重叠 |
| 开启 | Surface |
均为暗色 | 与状态栏重叠 |
| 开启 | Scaffold |
均为暗色 | 不再与状态栏重叠 |
结论:建议使用Edge-to-Edge + Scaffold Container模板取代Surface Container。
Jetpack Compose
Description
Jetpack Compose is Android's recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.Compose 属于 Jetpack 的分支,不同于传统 Jetpack 方式使用 XML 布局,属于声明式 UI 框架。
Jetpack Compose核心概念表
| 核心概念 | 通俗大白话 (是什么) | 核心关键词 (怎么记) |
|---|---|---|
@Composable |
UI 积木块。标记这只函数是用来画界面的。 | 函数式 UI、首字母大写、不能在普通函数里调用 |
Modifier |
衣服/皮肤。用来改尺寸、换皮肤、加点击事件。 | 链式调用、顺序决定一切、无 Margin 概念 |
State & Recomposition |
数据和刷新。数据变了,界面自动重新运行。 | 数据驱动、局部智能刷新、拒绝频繁触发 |
Declarative UI |
设计理念。只声明界面长什么样,不管怎么画。 | 告别 findViewById、状态同步、懒人式 UI |
Side-Effects |
安全防护锁。在频繁刷新的组件里安全搞网络请求。 | 生命周期感知、防重复触发、控制外部逻辑 |
@Composable
API reference | Android Developers
Composable functions are the fundamental building blocks of an application built with Compose.
Composable can be applied to a function or lambda to indicate that the function/lambda can be used as part of a composition to describe a transformation from application data into a tree or hierarchy.
Annotating a function or expression with Composable changes the type of that function or expression. For example, Composable functions can only ever be called from within another Composable function. A useful mental model for Composable functions is that an implicit "composable context" is passed into a Composable function, and is done so implicitly when it is called from within another Composable function. This "context" can be used to store information from previous executions of the function that happened at the same logical point of the tree.
词义
Compose: to combine together to form a whole
Composable:可组合的
语法
@Composable:注解,用来告诉编译器,这是一个用来标记、绘制UI页面的函数。
意义
@Composable 是 Jetpack Compose 的核心灵魂。被其修饰的函数被称为组件或Composable函数。
Q:判断一个函数是普通Kotlin函数还是Composable函数最简单的方法:
看函数名首字母
在规范的开发中,所有被 @Composable 修饰的函数,函数名的首字母都是大写的(例如 Greeting、Text、Surface),而我们平时写的普通 Kotlin 函数首字母通常是小写的(例如 onCreate、enableEdgeToEdge)。
Q:@Composable与普通函数的区别有哪些:
@Composableannotation before the function.@Composablefunction names are capitalized.@Composablefunctions can't return anything.
Modifier
An ordered, immutable collection of
modifier elementsthat decorate or add behavior to Compose UI elements. For example, backgrounds, padding and click event listeners decorate or add behavior to rows, text or buttons.
特点:
- 链式调用
简单使用方法参见Iteration2。
@Preview
API reference | Android Developers
To enable a preview of one composable, create another composable, annotated with `@Composable` and `@Preview`.The `@Preview` annotation tells Android Studio that this composable should be shown in the design view of this file.One of the primary benefits of using `@Preview` composables is to avoid reliance on the emulator in Android Studio. You can save the memory-heavy startup of the emulator for more final look-and-feel changes, and `@Preview`'s ability to make and test small code changes with ease.showBackground属性:值为 true时,为组件预览填充背景,否则背景为透明。
@Preview注解的函数一般在原函数后加Preview来命名。简单例子如下:
@Composable
fun SimpleComposable() {
Text("Hello World")
}
@Preview
@Composable
fun SimpleComposablePreview() {
SimpleComposable()
}
Iteration1
需求:change the background color. = 为文本框加上背景色填充。
步骤点:
1)找到 Greeting()函数中的文本框位置:Text()
- 选中
Text()并利用Android Studio中的快捷键:Alt+Enter快速添加容器
2)将默认的容器 Box替换为 Surface()
- 使用Surface()的
color属性,设置容器颜色 - 未引用依赖时,输入
Color会飘红
3)添加 androidx.compose.ui.graphics.Color依赖,并对依赖进行整理
- 可利用Top Toolbar -> Help -> Find Action,快速找到想使用的 Action
- 可利用Top Toolbar -> Code -> Optimize imports,快速删除未使用依赖
关于Action的讨论
IDE的设计哲学:万物皆为Action。 可以把 Android Studio 想象成一个巨大的**工具箱**,里面有上千个工具(按钮、菜单项、设置页)。平时你要找“格式化代码”这个工具,得先点开 `Code` 菜单,再往下找 `Reformat Code`。而 **Find Action** 相当于一个**语音遥控器**。你不需要知道这个工具放在哪个抽屉里,只要对着遥控器喊出功能的名字(如 “Format”),它立刻就把这个工具高亮送到你面前。Code:
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
// 使用Surface容器,缺点:会与状态栏重叠。
Surface(color = Color.Cyan) {
Text(
text = "Hi, my name is $name!",
modifier = modifier
)
}
}
Issue1
Surface()容器会与状态栏重叠。
错误归因:
没有注意到Greeting的Surface没有包含GreetingCard传下来的modifier。
Solution1
用 Scaffold()代替 Surface().
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
// 重构方法:使用Scaffold取代Surface
Scaffold(
modifier = modifier, // 将传入的 modifier 给最外层的容器
containerColor = Color.Red
) { innerPadding -> // Scaffold 会提供一个避开系统栏的 padding
Text(
text = "Hi, my name is $name!",
// 必须通过 Modifier.padding(innerPadding) 把安全边距应用到内部的 Text 上
modifier = Modifier.padding(innerPadding)
)
}
}
Problem: Scaffold占用的空间太大,不适合小组件。
⚠️小提示:
在实际开发中,Scaffold 通常被用作整个页面的根底座(也就是全屏显示)。
如果你只是想做一个局部的小卡片、小方块并改变它的宽高,官方更推荐使用 Surface 或 Box。因为 Scaffold 天生设计用来承载状态栏、导航栏等全屏组件,强行把它缩得很窄,它内部的计算可能会变得有些奇怪。
Solution2
在 text上加修饰符
Surface(
modifier = modifier.fillMaxSize(), // 让容器填满整个屏幕
color = Color.Cyan
) {
Text(
text = "Hi, my name is $name!",
// 仅仅让文字避开顶部状态栏
modifier = Modifier.statusBarsPadding()
)
}
Problem: 仅有文字避开了状态栏,Surface()容器还是会和状态栏重叠。
Solution3
在 Surface上加修饰符
Solution3.1:statusBarsPadding()
在 Surface()内加入修饰符 statusBarsPadding(),作用:自动去计算顶部状态栏的高度,并转化为对应的内边距(Padding),完美避开重叠。
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Surface(
// 将传入的 modifier 与 statusBarsPadding 链式拼接
modifier = modifier.statusBarsPadding(),
color = Color.Cyan
) {
Text(
text = "Hi, my name is $name!",
// 这里的 modifier 就不需要再重复处理状态栏了
)
}
}
Solution3.2:safeDrawingPadding()
一次性避开所有不安全区域。包括:顶部状态栏,底部导航栏,刘海屏,挖孔屏等。
Surface(
modifier = modifier.safeDrawingPadding(), // 自动避开四周所有系统栏和挖孔
color = Color.Cyan
) {
Text(text = "Hi, my name is $name!")
}
效果评价:
3>2>1
Best Solution:
在Surface参数中加入外层传进来的modifier
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Surface(
modifier = modifier,
color = MaterialTheme.colorScheme.primary // 从固定颜色修改成主题色
) {
Text(
text = "Hi, my name is $name!",
modifier = Modifier.padding(horizontal = 24.dp, vertical = 10.dp)
)
}
}
符合KISS原则。
Issue2
GreetingCardPreview()和 GreetingPreview()显示颜色不同。
原因:
GreetingCardPreview()未包裹GreetingCardTheme,使用的是系统最原始的默认色GreetingPreview()包裹了GreetingCardTheme,使用的是主题颜色
Iteration2
需求:add some space (padding) around the text. = 增加文本周围的填充空间。
介绍:
A
Modifieris used to augment or decorate a composable. One modifier you can use is thepaddingmodifier, which adds space around the element (in this case, adding space around the text). This is accomplished by using theModifier.padding()function.
步骤点:
1)为 modifier添加一个尺寸为 24.dp 的padding。
2)添加依赖
import androidx.compose.ui.unit.dp
import androidx.compose.foundation.layout.padding
Completed:
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Surface(
modifier = modifier.statusBarsPadding(),
color = Color.Cyan
) {
Text(
text = "Hi, my name is $name!",
modifier = modifier.padding(24.dp) // 新增行
)
}
}
Conclusion
Project1完结撒花。入门,看这么简单的项目很是享受。单文件,最简单皮实的文本框显示。
评论