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。
Iteration1:Color
需求: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:Padding
需求: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完结撒花。入门,看这么简单的项目很是享受。单文件,最简单皮实的文本框显示。
评论