前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >安卓软件开发:Jetpack Compose 和 Material 3 实现高级登录页面(Kotlin)

安卓软件开发:Jetpack Compose 和 Material 3 实现高级登录页面(Kotlin)

原创
作者头像
Nimyears
修改2024-09-15 07:55:08
4850
修改2024-09-15 07:55:08

2024年已经过半了,我作为聋人独立开发者,我经常会时不时反思:自己这半年到底进步了多少?在这篇文章里,我分享一个用 Jetpack Compose、Material3和 Kotlin 语言实现登录页面的案例。如果你有一定开发经验,相信这篇文章对你会非常有所帮助。

一、项目背景

Material 3 是 Google 的最新 UI 框架,以声明式 UI 构建方式取代了传统的 XML 布局,很大提升了编程效率,减少了许多繁琐的代码。本项目使用 Compose、Material 3和 Kotlin 语言,实现一个登录页面。

PS:适合已有编程基础的开发者,如果你是初学者,建议先看看我另一篇基础文章:安卓软件开发:用Java和Kotlin构建MDC-UI框架实现LoginUI(基础)-腾讯云开发者社区-腾讯云 (tencent.com)

1.1 项目需求分析

登录页面的基本结构:

两个文本字段:用于输入用户名和密码。

两个按钮:分别为“Cancel”按钮和“Next”按钮。

二、项目开发

2.1 添加项目依赖项

在项目的 build.gradle 文件中添加 Compose 和 Material 3 的依赖项:

代码语言:groovy
复制
dependencies {
    implementation libs.androidx.core.ktx
    implementation libs.androidx.lifecycle.runtime.ktx
    implementation libs.androidx.activity.compose
    implementation platform(libs.androidx.compose.bom)
    implementation libs.androidx.ui
    implementation libs.androidx.ui.graphics
    implementation libs.androidx.ui.tooling.preview
    implementation libs.androidx.material3
    testImplementation libs.junit
    androidTestImplementation libs.androidx.junit
    androidTestImplementation libs.androidx.espresso.core
    androidTestImplementation platform(libs.androidx.compose.bom)
    androidTestImplementation libs.androidx.ui.test.junit4
    debugImplementation libs.androidx.ui.tooling
    debugImplementation libs.androidx.ui.test.manifest
}

[versions]
agp = "8.6.0"
kotlin = "1.9.0"
coreKtx = "1.13.1"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
lifecycleRuntimeKtx = "2.8.3"
activityCompose = "1.9.0"
composeBom = "2024.04.01"

//grade/libs.versions.toml
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

2.2 初始化 Compose 项目

下载依赖项添加完成后,保证该项目设置了使用Jetpack Compose,通过配置 MainActivity以Compose语糖风格绑定启动UI:

代码语言:java
复制
@Composable
fun MainScreen() {
    Scaffold {
        LoginScreen()
    }
}

2.3 创建登录页面

代码语言:java
复制
@Composable
fun LoginScreen() {
    var username by remember { mutableStateOf("") }
    var password by remember { mutableStateOf("") }
    var error by remember { mutableStateOf("") }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text("Nim", style = MaterialTheme.typography.displayMedium)

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

        TextField(
            value = username,
            onValueChange = { username = it },
            label = { Text("Username") },
            singleLine = true
        )

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

        TextField(
            value = password,
            onValueChange = { password = it },
            label = { Text("Password") },
            singleLine = true,
            visualTransformation = PasswordVisualTransformation()
        )

        if (error.isNotEmpty()) {
            Text(text = error, color = Color.Red, style = MaterialTheme.typography.bodyMedium)
        }

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

        Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
            Button(onClick = { }) {
                Text("Cancel")
            }

            Button(onClick = {
                if (password.length < 8) {
                    error = "密码必须至少为8个字符。"
                } else {
                    error = ""
                }
            }) {
                Text("Next")
            }
        }
    }
}

2.4 review 知识点介绍

它可以让你在Android Studio中实时看到你编写的 UI 组件,不必要每次重新运行应用。这对我们调试和调整界面非常有帮助。

2.4.1 @Preview 的基本用法

@Preview 注解一般用在 @Composable 函数上方,用于标记函数的 UI 布局可以在 Android Studio 的预览窗口中显示。以下是预览函数的基本结构:

代码语言:java
复制
@Preview(showBackground = true)
@Composable
fun LoginScreenPreview() {
    NimLoginTheme {
        LoginScreen()
    }
}

@Preview 像是一个小窗口,帮我们展示 @Composable 函数的实际渲染效果。只要在代码上方加上 @Preview,就能在 Android Studio 的右侧看到你想看的UI效果。

2.5 效果图

2.6完整代码

代码语言:java
复制
package com.nim.nimlogin

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.nim.nimlogin.ui.theme.NimLoginTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            NimLoginTheme {
                LoginScreen()
            }
        }
    }
}

@Composable
fun LoginScreen() {
    var username by remember { mutableStateOf("") }
    var password by remember { mutableStateOf("") }
    var error by remember { mutableStateOf("") }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text("Nim", style = MaterialTheme.typography.displayMedium)

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

        TextField(
            value = username,
            onValueChange = { username = it },
            label = { Text("Username") },
            singleLine = true
        )

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

        TextField(
            value = password,
            onValueChange = { password = it },
            label = { Text("Password") },
            singleLine = true,
            visualTransformation = PasswordVisualTransformation()
        )

        if (error.isNotEmpty()) {
            Text(text = error, color = Color.Red, style = MaterialTheme.typography.bodyMedium)
        }

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

        Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
            Button(onClick = {
                // 清除输入
                username = ""
                password = ""
                error = ""
            }) {
                Text("Cancel")
            }

            Button(onClick = {
                if (password.length < 8) {
                    error = "密码必须至少为8个字符。"
                } else {
                    error = ""
                }
            }) {
                Text("Next")
            }
        }
    }
}
@Preview(showBackground = true)
@Composable
fun LoginScreenPreview() {
    NimLoginTheme {
        LoginScreen()
    }
}

2.7视频演示如下:

视频内容

三、技术难点

3.1 UI 状态管理与实时反馈

难点:和传统 XML 的状态管理不同,Compose 使用 remembermutableStateOf 管理 UI 状态。如何实时更新界面,确保用户输入体验流畅。

解决方案:使用 remembermutableStateOf 保持组件状态,确保状态变化时界面自动更新。

3.2 输入验证与错误提示

难点:实现实时输入验证且提供用户友好的错误提示,防止错误状态被延迟或丢失。

解决方案:在 onValueChange 中处理输入验证,通过动态更新错误提示提升用户体验。利用 TextColor 的组合,要多思考怎么设计直观的错误提示样式。

3.3 声明式导航与组件解耦

难点:在 Compose 中,声明式导航和传统的 FragmentActivity 导航有很大区别,特别是在状态的保留和恢复。

解决方案:使用 Navigation Compose 进行页面管理,通过 NavHost 实现页面的解耦和状态管理,使得 UI 流程更顺畅、维护很方便。

四、学习笔记

我加深了对 Jetpack Compose 的理解,还掌握了如何在实际项目中灵活使用状态管理和组件解耦。我值得分享经验:

  1. 声明式编程的优势:Compose 通过声明式编程减少了很多冗余代码,所有 UI 逻辑都和状态紧密绑定,开发起来更直观。
  2. Material 3 组件和Compose 的结合:Material 3 提供了很多现代化的 UI 组件,像 ScaffoldTopAppBar 各等,上手体验非常好,让 UI 更美观一致。
  3. 简化的 UI 状态管理:Compose 的 State 管理相比传统的 LiveDataViewModel 更灵活,且能更好集成在 UI 交互场景。

五、总结和展望

通过本篇文章的实践,我体验到了 Jetpack Compose 的强大好处是Jetpack Compose声明式编程带来的直观、简化的 UI 构建、灵活的状态管理,以及 Material 3 组件的强大。让我对未来的开发充满了很多期待。相信 Jetpack Compose 在未来几年成为 Android UI 开发的主流工具,希望这篇文章能对大家有所帮助!!

六、我的作品集

可以参考下,请见GitHub 仓库 - GitHub - jienian/CHAPTS,内容包括Kotlin、ComposeM3 等技术实现。

有任何问题欢迎提问,感谢大家阅读 )

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、项目背景
    • 1.1 项目需求分析
    • 二、项目开发
      • 2.1 添加项目依赖项
        • 2.2 初始化 Compose 项目
          • 2.3 创建登录页面
            • 2.4 review 知识点介绍
              • 2.4.1 @Preview 的基本用法
                • 2.5 效果图
                  • 2.6完整代码
                    • 2.7视频演示如下:
                    • 三、技术难点
                      • 3.1 UI 状态管理与实时反馈
                        • 3.2 输入验证与错误提示
                          • 3.3 声明式导航与组件解耦
                          • 四、学习笔记
                          • 五、总结和展望
                          • 六、我的作品集
                          相关产品与服务
                          云开发 CloudBase
                          云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档