
什么是Compose
Jetpack Compose 是用于构建原生 Android 界面的新工具包。它使用更少的代码、强大的工具和直观的 Kotlin API,可以帮助您简化并加快 Android 界面开发,打造生动而精彩的应用。
Compose的优势
- 更少的代码: 编写代码只需要采用 Kotlin,而不必拆分成 Kotlin 和 XML 部分,所有代码都位于同一文件中(而不是在 Kotlin 和 XML 语言之间来回切换)时,跟踪变得更容易。
- 直观: 利用 Compose,您可以构建不与特定 activity 或 fragment 相关联的小型无状态组件。
- 加速开发: Compose 与您所有的现有代码兼容:您可以从 View 调用 Compose 代码,也可以从 Compose 调用 View。大多数常用库(如 Navigation、ViewModel 和 Kotlin 协程)都适用于 Compose,因此您可以随时随地开始采用。
- 功能强大: Compose 不仅解决了声明性界面的问题,还改进了无障碍功能 API、布局等各种内容。
Compose的上手成本
XML与Compose对比,代码如下:
<LinearLayout android:orientation="vertical">
<TextView android:text="Hello" />
<TextView android:text="World" />
</LinearLayout>
Column {
Text("Hello")
Text("World")
}
通过对比感觉并没有太大的区别,也就是说Compose的上手成本很低(老安卓er狂喜 ),接下来就跟随我一起编写一个简单的登录页面吧。
将 Jetpack Compose 添加到应用中
为了您能正常运行本项目,请使用 Android Studio Chipmunk (2021.2.1) 🐿️
和 Android Gradle 7.2.2
或者以上版本。
Download Android Studio | Android Developer
配置Android Gradle 插件,如下所示:
buildscript {
...
dependencies {
classpath "com.android.tools.build:gradle:7.2.2"
...
}
}
在应用的 build.gradle
文件中启用 Jetpack Compose,如下所示:
android {
buildFeatures {
// Enables Jetpack Compose for this module
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.3.0'
}
}
复制代码
在应用的 build.gradle
文件中添加 Jetpack Compose 工具包依赖项,如下所示:
dependencies {
// Integration with activities
implementation 'androidx.activity:activity-compose:1.5.1'
// Compose Material Design
implementation 'androidx.compose.material:material:1.2.1'
// Animations
implementation 'androidx.compose.animation:animation:1.2.1'
// Tooling support (Previews, etc.)
implementation 'androidx.compose.ui:ui-tooling:1.2.1'
// Integration with ViewModels
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1'
// UI Tests
androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.2.1'
}
开始改造登录界面
这是一个常见登录界面的设计图,如下所示:

我们通过ConstraintLayout来进行布局,并把按钮和输入框等组合项摆放到对应的位置,代码如下:
ConstraintLayout(
modifier = Modifier
.fillMaxSize()
.paint(
painter = painterResource(id = R.drawable.bg),
contentScale = ContentScale.FillBounds
)
.padding(start = 40.dp, end = 40.dp)
.systemBarsPadding() //设置系统状态栏Padding
) {
//为每个可组合项创建引用
val (black, welcome, wan, username, password, login, sign_in, sign_up) = createRefs()
//为login组合项创建Top屏障线
val loginTopBarrier = createTopBarrier(login)
//为login组合项创建Bottom屏障线
val loginBottomBarrier = createBottomBarrier(login)
......
}
使用Image创建返回按钮,代码如下:
Image(
//设置图片
painter = painterResource(R.drawable.ic_back),
contentDescription = null,
modifier = Modifier
//设置尺寸
.size(15.dp)
//将black分配给可组合按钮,并将其约束到ConstraintLayout的顶部
.constrainAs(black) {
//top约束,间距15dp
top.linkTo(parent.top, margin = 15.dp)
}
//点击事件
.clickable {
navigation(Router.MAIN)
}
)
使用Text创建"Welcome",代码如下:
Text(
text = "Welcome",
style = MaterialTheme.typography.h4,
color = colorResource(R.color.white),
//将welcome分配给可组合按钮,并将其约束到black的底部
modifier = Modifier
.constrainAs(welcome) {
top.linkTo(black.bottom, 60.dp)
}
)
使用TextField创建输入框,代码如下:
var usernameText by rememberSaveable { mutableStateOf("") }
TextField(
value = usernameText,
onValueChange = {
usernameText = it
},
placeholder = {
Text("请输入用户名")
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
disabledIndicatorColor = colorResource(id = R.color.white),
unfocusedIndicatorColor = colorResource(id = R.color.white),
focusedIndicatorColor = colorResource(id = R.color.white),
focusedLabelColor = colorResource(id = R.color.white),
errorIndicatorColor = colorResource(id = R.color.white),
placeholderColor = colorResource(id = R.color.text_ccc),
textColor = colorResource(id = R.color.text_fff),
cursorColor = colorResource(id = R.color.white)
),
//将username分配给可组合按钮,并将其约束到password的顶部
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.constrainAs(username) {
bottom.linkTo(password.top, 25.dp)
}
)
使用Image创建登录按钮,代码如下:
Image(
//设置图片
painter = painterResource(R.drawable.ic_right_arrow),
contentDescription = null,
modifier = Modifier
//剪裁成圆形
.clip(CircleShape)
//设置背景颜色
.background(colorResource(R.color.theme_orange))
.size(75.dp)
.padding(25.dp)
//将login分配给可组合按钮,并将其约束到ConstraintLayout的右侧、sign_up的顶部
.constrainAs(login) {
end.linkTo(parent.end)
bottom.linkTo(sign_up.top, 60.dp)
}
//点击事件
.clickable {
if (checkParameter(usernameText, passwordText)) {
viewModel.login(usernameText, passwordText)
}
}
)
使用Text创建"登录"文字并使用屏障线进行约束,代码如下:
//创建登录按钮顶部的屏障线
val loginTopBarrier = createTopBarrier(login)
//创建登录按钮底部的屏障线
val loginBottomBarrier = createBottomBarrier(login)
Text(
text = "登录",
fontSize = 25.sp,
color = colorResource(R.color.white),
modifier = Modifier
//将sign_in分配给可组合按钮,并将其约束到loginTopBarrier和loginBottomBarrier之间
.constrainAs(sign_in) {
top.linkTo(loginTopBarrier)
bottom.linkTo(loginBottomBarrier)
}
)
使用Text创建去注册,代码如下:
Text(
text = "去注册",
//设置下划线
textDecoration = TextDecoration.Underline,
fontSize = 16.sp,
color = colorResource(R.color.white),
//将sign_up分配给可组合按钮,并将其约束到ConstraintLayout的底部
modifier = Modifier
.constrainAs(sign_up) {
bottom.linkTo(parent.bottom, 40.dp)
}
//点击事件
.clickable {
navigation(Router.USER_REGISTER)
}
)
最后完整代码如下:
@Composable
fun UserLoginPage() {
var usernameText by rememberSaveable { mutableStateOf("") }
var passwordText by rememberSaveable { mutableStateOf("") }
ConstraintLayout(
modifier = Modifier
.fillMaxSize()
.paint(
painter = painterResource(id = R.drawable.bg),
contentScale = ContentScale.FillBounds
)
.padding(start = 40.dp, end = 40.dp)
.systemBarsPadding()
) {
val (black, welcome, wan, username, password, login, sign_in, sign_up) = createRefs()
val loginTopBarrier = createTopBarrier(login)
val loginBottomBarrier = createBottomBarrier(login)
Image(
painter = painterResource(R.drawable.ic_back),
contentDescription = null,
modifier = Modifier
.size(15.dp)
.constrainAs(black) {
top.linkTo(parent.top, margin = 15.dp) //top约束
}
.clickable { //点击事件
navigation(Router.MAIN)
}
)
Text(
text = "Welcome",
style = MaterialTheme.typography.h4,
color = colorResource(R.color.white),
modifier = Modifier
.constrainAs(welcome) {
top.linkTo(black.bottom, 60.dp)
}
)
Text(
text = "玩Android",
style = MaterialTheme.typography.h5,
color = colorResource(R.color.white),
modifier = Modifier
.constrainAs(wan) {
top.linkTo(welcome.bottom, 10.dp)
}
)
TextField(
value = usernameText,
onValueChange = {
usernameText = it
},
placeholder = {
Text("请输入用户名")
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
disabledIndicatorColor = colorResource(id = R.color.white),
unfocusedIndicatorColor = colorResource(id = R.color.white),
focusedIndicatorColor = colorResource(id = R.color.white),
focusedLabelColor = colorResource(id = R.color.white),
errorIndicatorColor = colorResource(id = R.color.white),
placeholderColor = colorResource(id = R.color.text_ccc),
textColor = colorResource(id = R.color.text_fff),
cursorColor = colorResource(id = R.color.white)
),
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.constrainAs(username) {
bottom.linkTo(password.top, 25.dp)
}
)
TextField(
value = passwordText,
onValueChange = {
passwordText = it
},
placeholder = {
Text("请输入用户密码")
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
disabledIndicatorColor = colorResource(id = R.color.white),
unfocusedIndicatorColor = colorResource(id = R.color.white),
focusedIndicatorColor = colorResource(id = R.color.white),
focusedLabelColor = colorResource(id = R.color.white),
errorIndicatorColor = colorResource(id = R.color.white),
placeholderColor = colorResource(id = R.color.text_ccc),
textColor = colorResource(id = R.color.text_fff),
cursorColor = colorResource(id = R.color.white)
),
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.constrainAs(password) {
bottom.linkTo(login.top, 25.dp)
}
)
Text(
text = "登录",
fontSize = 25.sp,
color = colorResource(R.color.white),
modifier = Modifier
.constrainAs(sign_in) {
top.linkTo(loginTopBarrier)
bottom.linkTo(loginBottomBarrier)
}
)
Image(
painter = painterResource(R.drawable.ic_right_arrow),
contentDescription = null,
modifier = Modifier
.clip(CircleShape)
.background(colorResource(R.color.theme_orange))
.size(75.dp)
.padding(25.dp)
.constrainAs(login) {
end.linkTo(parent.end)
bottom.linkTo(sign_up.top, 60.dp)
}
.clickable {
if (checkParameter(usernameText, passwordText)) {
viewModel.login(usernameText, passwordText)
}
}
)
Text(
text = "去注册",
textDecoration = TextDecoration.Underline,
fontSize = 16.sp,
color = colorResource(R.color.white),
modifier = Modifier
.constrainAs(sign_up) {
bottom.linkTo(parent.bottom, 40.dp)
}
.clickable {
navigation(Router.USER_REGISTER)
}
)
}
}
如何预览
借助 @Preview
注解,您可以在 Android Studio 中预览可组合函数,而无需构建应用并将其安装到 Android 设备或模拟器中。
该注解必须用于不接受参数的可组合函数。
请在 @Composable
上方添加 @Preview
注解。
@Preview()
@Composable
fun UserLoginPagePreview() {
MaterialTheme {
UserLoginPage()
}
}
Thanks
以上就是本篇文章的全部内容,如有问题欢迎指出,我们一起进步。
为方便大家系统的学习 Android Compose ,这里特意联合了腾讯 T12级专家和谷歌技术团队共同整理了一份 《Jetpack Compose 入门到精通》的学习手册,该手册条理清晰,含图像化表示更加易懂,非常适合想要进阶提升的伙伴,有需要的可以直接点击此处↓↓↓进行参考学习!!!
有需要的可以复制下方链接,传送直达!!!
https://qr21.cn/CaZQLo?BIZ=ECOMMERCE
一、Jetpack Compose入门详解
1.优势与缺点
2.Jetpack Compose 四节课
3.标准布局组件
4.xml和compose混合使用 + livedata数据绑定
5.compose结合navigation使用
6.Compose 中的 ConstraintLayout
7.Compose 手写一个分享二维码弹窗
8.Compose 设置颜色的三种方式
9.Compose事件与状态简略介绍
10.Compose中的预览@Preview与@PreviewParameter的使用

二、Compose学习笔记录
1.基本控件
2.Composable和MutableState
3.重组和无状态
4.状态机制和重组优化
5.derivedStateOf和remember的使用
6.CompositionLocal的应用场景
7.Compose动画之AnimateSpec
8.Compose动画之DecayAnimation
9.Compose动画之中止和入场效果

三、Android Compose 动画使用详解
1.Compose 中属性动画的使用探索
2.状态改变动画animateXxxAsState
3.自定义animateXxxAsState动画

Compose 需要学习的知识点还有许多,这还得一一的去探究其中的奥秘,该学习手册的内容还在持续更新中,有需要的可以直接点击此处↓↓↓进行参考学习!!!
有需要的可以复制下方链接,传送直达!!!
https://qr21.cn/CaZQLo?BIZ=ECOMMERCE
网友评论