美文网首页Android技术知识
Jetpack Compose : 从改造登录页面开始

Jetpack Compose : 从改造登录页面开始

作者: 搬砖小老弟 | 来源:发表于2022-10-20 15:26 被阅读0次

什么是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

相关文章

网友评论

    本文标题:Jetpack Compose : 从改造登录页面开始

    本文链接:https://www.haomeiwen.com/subject/qryuzrtx.html