前言
在上一篇文章中,我说将运用Jetpack Compose仿微信UI来开端我的Jetpack Compose学习之旅,咱们都知道,微信是一个庞大的系统,页面许多,我仅仅挑选一些页面去完成,这一期我将完成微信的登陆页UI。在学习了compose根底组件之后,我发现和 flutter 很像,比如Text,Row,Column等,就连在 flutter 常用的脚手架Scaffold也有,或许都是同一个爹的原因(都出自谷歌),所以运用起来也是比较容易的。
页面构成
登陆模块涉及的页面许多,我首要完成的页面包含:登陆主页(当咱们退出登陆来到的页面),登陆其他帐号和手机号登陆三个页面。我将运用一个Activity和三个组合函数页面构成。
作用图
登陆主页
登陆其他帐号底部弹窗
登陆其他帐号页面
手机号登陆页面
代码完成
我先创立一个LoginNavScreen,它包含登陆主页,登陆其他帐页面和手机号登陆页面,内部运用navigation跳转对应的页面,完成代码如下:
@Composable
fun LoginNavScreen() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = LOGIN //默认的发动页
) {
composable(route = LOGIN) {
LoginScreen(navController = navController)
}
composable(route = LOGIN_OTHER) {
LoginOtherScreen(navController = navController)
}
composable(
route = "$LOGIN_PHONE/{phone}",
arguments = listOf(navArgument("phone") {
type = NavType.StringType
})
) {
val phone = it.arguments?.getString("phone") ?: ""
LoginPhoneScreen(navController = navController, phone = phone)
}
}
}
登陆主页的完成
这个页面的布局比较简单,首要包含头像,手机号,暗码(验证码)输入框,暗码和验证码切换,登陆按钮和底部三个选项构成,代码完成如下:
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter", "CoroutineCreationDuringComposition")
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
@Composable
fun LoginScreen(navController: NavHostController) {
val context = LocalContext.current as Activity
rememberSystemUiController().setStatusBarColor(Color.Transparent, darkIcons = true)
val password = EasyDataStore.getData("password", "")
var pwdText by remember { mutableStateOf(password) }
val loading = remember { mutableStateOf(false) }
var isFocus by remember { mutableStateOf(false) }
var isPwdAuth by remember { mutableStateOf(true) }
val scope = rememberCoroutineScope()
val modalBottomSheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
Surface(
Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.autoCloseKeyboard()
) {
Scaffold(
content = { innerPadding ->
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(0xffEDEDED))
.padding(innerPadding)
) {
LazyColumn(contentPadding = innerPadding) {
/**
* 导航栏到头像的距离
*/
item {
Spacer(modifier = Modifier.height(50.dp))
}
/**
* 头像
*/
item {
Box(
modifier = Modifier.height(70.dp)
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
Image(
painter = rememberCoilPainter(request = myAvatar),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.size(70.dp)
)
}
}
/**
* 手机号
*/
item {
Box(
modifier = Modifier
.wrapContentHeight()
.fillMaxWidth()
.padding(top = 10.dp, bottom = 40.dp),
contentAlignment = Alignment.Center
) {
Text(
text = "18230000000",
fontSize = 18.sp
)
}
}
/**
* 暗码输入框
*/
item {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 15.dp, end = 15.dp)
.wrapContentHeight(),
) {
TextField(
value = pwdText,
onValueChange = {
pwdText = it
},
colors = TextFieldDefaults.outlinedTextFieldColors(
containerColor = Color.Transparent,
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
cursorColor = Color(0xff5ECC71)
),
textStyle = TextStyle(
fontSize = 16.sp
),
leadingIcon = {
Text(
text = if (isPwdAuth) "暗码" else "验证码",
fontSize = 18.sp,
modifier = Modifier.width(90.dp)
)
},
modifier = Modifier.fillMaxWidth().onFocusChanged {
isFocus = when {
it.isFocused -> true
else -> false
}
},
placeholder = {
Text(
text = if (isPwdAuth) "请填写微信暗码" else "请填写验证码",
fontSize = 16.sp,
color = Color(0xff888888),
)
}
)}
}
/**
* 获取验证码
*/
item {
if (!isPwdAuth) {
Box(
modifier = Modifier
.padding(start = 110.dp, end = 15.dp, bottom = 4.dp)
.fillMaxWidth(),
contentAlignment = Alignment.CenterStart
) {
Text(
text = "获取验证码",
fontSize = 16.sp,
modifier = Modifier
.wrapContentHeight()
.wrapContentWidth()
.clip(RoundedCornerShape(8.dp))
.background(Color(0xffE1E1E1))
.padding(
start = 10.dp,
top = 2.dp,
end = 10.dp,
bottom = 6.dp
)
)
}
}
}
/**
* 手机号底部的下划线
*/
item {
Box(modifier = Modifier.padding(start = 15.dp, end = 15.dp)) {
CQDivider(thickness = 1.dp, colorId = if (isFocus) R.color.green else R.color.gray_10)
}
}
item {
Text(
text = if (isPwdAuth) "用短信验证码登陆" else "暗码登陆",
fontSize = 14.sp,
color = Color(0xff5F6594),
modifier = Modifier
.padding(15.dp)
.clickable {
isPwdAuth = !isPwdAuth
}
)
}
item {
Box(
modifier = Modifier
.padding(top = 40.dp)
.fillMaxWidth()
.wrapContentHeight(),
contentAlignment = Alignment.Center
) {
Text(
text = "登陆",
fontSize = 16.sp,
color = Color.White,
modifier = Modifier
.wrapContentHeight()
.wrapContentWidth()
.clip(RoundedCornerShape(8.dp))
.background(Color(0xff5ECC71))
.padding(
top = 10.dp,
bottom = 10.dp,
start = 80.dp,
end = 80.dp
)
.click {
if (pwdText == "") {
context.toast(if (isPwdAuth) "请输入暗码" else "请输入验证码")
return@clickable
}
if (pwdText != "123456") {
context.toast(if (isPwdAuth) "暗码不正确" else "验证码不正确")
return@clickable
}
loading.value = true
scope.launch {
delay(2000)
loading.value = false
MainActivity.navigate(context)
EasyDataStore.putData("password", pwdText)
}
},
textAlign = TextAlign.Center
)
}
}
item {
if (loading.value) {
ProcessDialogComponent(
loading = loading,
content = "正在登陆..."
)
}
}
}
/**
* 底部布局(找回暗码等)
*/
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.BottomCenter) {
Column(modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
horizontalAlignment = Alignment.CenterHorizontally
) {
/**
* 中心的分割线
*/
Row(
modifier = Modifier
.wrapContentWidth()
.padding(top = 60.dp)
) {
Text(
text = "找回暗码",
fontSize = 16.sp,
color = Color(0xff5F6594),
modifier = Modifier
.wrapContentWidth()
.padding(top = 15.dp, end = 15.dp),
)
Box(modifier = Modifier
.height(50.dp)
.width(0.5.dp)
.padding(top = 15.dp, bottom = 8.dp)
.background(Color(0xff888888))
)
Text(
text = "紧急结冻",
fontSize = 16.sp,
color = Color(0xff5F6594),
modifier = Modifier.wrapContentWidth()
.padding(top = 15.dp, start = 15.dp, end=15.dp),
)
Box(modifier = Modifier
.height(50.dp)
.width(0.5.dp)
.padding(top = 15.dp, bottom = 8.dp)
.background(Color(0xff888888))
)
Text(
text = "更多",
fontSize = 16.sp,
color = Color(0xff5F6594),
modifier = Modifier
.wrapContentWidth()
.padding(top = 15.dp, start = 15.dp)
.click {
scope.launch { modalBottomSheetState.show() }
},
textAlign = TextAlign.Start
)
}
}
}
}
/**
* 底部更多弹窗
*/
ModalBottomSheetDialog(
titles = listOf("登陆其他帐号","注册","安全问题","反应问题"),
coroutineScope = scope,
modalBottomSheetState = modalBottomSheetState,
onSelect = {index, title ->
Log.d("LoginScreen", "index====$index title=====$title")
// 导航到登陆其他帐号
if (index == 0) {
navController.navigate(LOGIN_OTHER)
}
}
)
}
)
}
}
ModalBottomSheetDialog
ModalBottomSheetDialog是我封装的底部挑选弹窗,完成的代码如下:
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ModalBottomSheetDialog(
titles: List<String>,
coroutineScope: CoroutineScope,
modalBottomSheetState: ModalBottomSheetState,
onSelect: (index: Int, title: String) -> Unit
){
ModalBottomSheetLayout(
sheetState = modalBottomSheetState,
sheetShape = RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp),
sheetContent = {
Column(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
) {
titles.forEachIndexed { index, title ->
Box(
modifier = Modifier.fillMaxWidth().height(45.dp)
.clickable {
onSelect(index, title)
coroutineScope.launch { modalBottomSheetState.hide() }
},
contentAlignment = Alignment.Center
) {
Text(text = title,
modifier = Modifier
.wrapContentWidth()
.wrapContentHeight(),
fontSize = 16.sp,
textAlign = TextAlign.Center
)
}
CQDivider()
}
Spacer(
modifier = Modifier
.height(10.dp)
.fillMaxWidth()
.background(Color(0xffF7F7F7))
)
Box(
modifier = Modifier.fillMaxWidth().height(45.dp),
contentAlignment = Alignment.Center
) {
Text(
text = "撤销",
modifier = Modifier
.wrapContentWidth()
.wrapContentHeight()
.clickable {
coroutineScope.launch { modalBottomSheetState.hide() }
},
fontSize = 16.sp,
textAlign = TextAlign.Center
)
}
}
}
) {}
}
细节优化
当咱们运用Modifier.clickable{}处理组件的点击事情时,会呈现说波纹作用,体会不是很好,在这儿我封装了Modifier的拓宽函数,代码如下:
**
* 自定义去掉水波纹的点击拓宽函数
*
* example Modifier.click{ doSomething() }
*/
fun Modifier.click(
onClick: () -> Unit
): Modifier = composed {
this.clickable(
indication = null,
onClick = onClick,
interactionSource = remember {
MutableInteractionSource()
}
)
}
登陆其他帐号
咱们是在底部的“更多”跳转登陆其他帐号的,
相关代码
Text(
text = "更多",
fontSize = 16.sp,
color = Color(0xff5F6594),
modifier = Modifier
.wrapContentWidth()
.padding(top = 15.dp, start = 15.dp)
.click {
/**
* 显现底部弹窗
*/
scope.launch { modalBottomSheetState.show() }
},
textAlign = TextAlign.Start
)
ModalBottomSheetDialog(
titles = listOf("登陆其他帐号","注册","安全问题","反应问题"),
coroutineScope = scope,
modalBottomSheetState = modalBottomSheetState,
onSelect = {index, title ->
Log.d("LoginScreen", "index====$index title=====$title")
/**
* 导航到登陆其他帐号
*/
if (index == 0) {
navController.navigate(LOGIN_OTHER)
}
}
)
登陆其他帐号页面的完成
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LoginOtherScreen(navController: NavHostController) {
val context = LocalContext.current as Activity
rememberSystemUiController().setStatusBarColor(Color.Transparent, darkIcons = true)
var isPhone by remember { mutableStateOf(true) }
var phoneText by remember { mutableStateOf("")}
var pwdOrPhoneText by remember { mutableStateOf("") }
val loading = remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
Surface(
Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.autoCloseKeyboard()
) {
Scaffold(
topBar = {
TopAppBar(
title = {},
navigationIcon = {
IconButton(
onClick = {
//返回上一页
navController.popBackStack()
}) {
Icon(
imageVector = Icons.Filled.Close,
contentDescription = null,
modifier = Modifier.size(28.dp),
)
}
}
)
},
content = { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
LazyColumn(contentPadding = innerPadding) {
/**
* 导航栏到title的距离
*/
item {
Spacer(modifier = Modifier.height(20.dp))
}
/**
* 手机号登陆title
*/
item {
Box(
modifier = Modifier
.height(50.dp)
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
Text(
text = if (isPhone) "手机号登陆" else "微信号/QQ号/邮箱登陆",
fontSize = 20.sp
)
}
}
/**
* 手机号输入框
*/
item {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 15.dp, end = 15.dp)
.wrapContentHeight(),
) {
TextField(
readOnly = isPhone,
value = phoneText,
onValueChange = {
phoneText = it
},
colors = TextFieldDefaults.outlinedTextFieldColors(
containerColor = Color.Transparent,
focusedBorderColor = Color.White,
unfocusedBorderColor = Color.White,
),
textStyle = TextStyle(
fontSize = 16.sp
),
leadingIcon = {
Text(
text = if (isPhone) "国家/区域" else "帐号",
fontSize = 18.sp,
modifier = Modifier.width(if (isPhone) 120.dp else 90.dp)
)
},
modifier = Modifier.fillMaxWidth(),
placeholder = {
Text(
text = if (!isPhone) "请填写微信号/QQ号/..." else "中国大陆(+86)",
fontSize = 16.sp,
color = Color(0xff888888),
)
}
)}
}
/**
* 手机号底部的下划线
*/
item {
Box(modifier = Modifier.padding(start = 15.dp, end = 15.dp)) {
CQDivider(thickness = 1.dp)
}
}
/**
* 暗码输入框
*/
item {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 15.dp, end = 15.dp)
.wrapContentHeight(),
) {
TextField(
value = pwdOrPhoneText,
onValueChange = {
pwdOrPhoneText = it
},
colors = TextFieldDefaults.outlinedTextFieldColors(
containerColor = Color.Transparent,
focusedBorderColor = Color.Green,
unfocusedBorderColor = Color(0xff888888),
cursorColor = Color.Green
),
textStyle = TextStyle(
fontSize = 16.sp
),
leadingIcon = {
Text(
text = if (isPhone) "手机号" else "暗码",
fontSize = 18.sp,
modifier = Modifier.width(if (isPhone) 120.dp else 90.dp)
)
},
modifier = Modifier.fillMaxWidth(),
placeholder = {
Text(
text = if (isPhone)"请填写手机号" else "请填写暗码",
fontSize = 16.sp,
color = Color(0xff888888),
)
}
)}
}
item {
Text(
text = if (!isPhone) "用手机号登陆" else "微信号/QQ号/邮箱登陆",
fontSize = 16.sp,
color = Color(0xff5F6594),
modifier = Modifier.padding(15.dp)
.clickable {
isPhone = !isPhone
}
)
}
item {
if (loading.value) {
ProcessDialogComponent(
loading = loading,
content = "正在登陆..."
)
}
}
}
/**
* 底部布局(登陆按钮,找回暗码等)
*/
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.BottomCenter) {
Column(modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()) {
Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(bottom = 20.dp),
contentAlignment = Alignment.Center
) {
Text(
text = if (isPhone) "上述手机号仅用于验证登陆" else "上述微信号/QQ号/邮箱登陆仅用于验证登陆",
fontSize = 12.sp,
color = Color(0xff888888),
)
}
Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
contentAlignment = Alignment.Center
) {
Text(
text = "同意并持续",
fontSize = 16.sp,
color = Color.White,
modifier = Modifier
.wrapContentHeight()
.wrapContentWidth()
.clip(RoundedCornerShape(8.dp))
.background(Color(0xff5ECC71))
.padding(
top = 10.dp,
bottom = 10.dp,
start = 80.dp,
end = 80.dp
)
.clickable {
if (phoneText == "" && !isPhone) {
context.toast("请输入帐号")
return@clickable
}
if (pwdOrPhoneText == "") {
context.toast(if (isPhone) "请输入手机号" else "请输入暗码")
return@clickable
}
if (isPhone) {
// 导航到手机登陆页
navController.navigate(
"$LOGIN_PHONE/$pwdOrPhoneText",
)
} else {
loading.value = true
scope.launch {
delay(2000)
loading.value = false
MainActivity.navigate(context)
}
}
},
textAlign = TextAlign.Center
)
}
/**
* 中心的分割线
*/
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 60.dp)
) {
Text(
text = "找回暗码",
fontSize = 16.sp,
color = Color(0xff5F6594),
modifier = Modifier
.padding(15.dp)
.weight(1f),
textAlign = TextAlign.End
)
Box(modifier = Modifier
.height(50.dp)
.width(0.5.dp)
.padding(top = 15.dp, bottom = 8.dp)
.background(Color(0xff888888))
)
Text(
text = "更多选项",
fontSize = 16.sp,
color = Color(0xff5F6594),
modifier = Modifier
.padding(15.dp)
.weight(1f),
textAlign = TextAlign.Start
)
}
}
}
}
}
)
}
}
手机号登陆页面的完成
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LoginPhoneScreen(navController: NavHostController, phone: String) {
val context = LocalContext.current as Activity
rememberSystemUiController().setStatusBarColor(Color.Transparent, darkIcons = true)
var phoneText by remember { mutableStateOf("+86$phone") }
var pwdText by remember { mutableStateOf("") }
val loading = remember { mutableStateOf(false) }
var isPwdAuth by remember { mutableStateOf(true) }
var isFocus by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
Surface(
Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.autoCloseKeyboard()
) {
Scaffold(
topBar = {
TopAppBar(
title = {},
navigationIcon = {
IconButton(
onClick = {
//返回上一页
navController.popBackStack()
}) {
Icon(
imageVector = Icons.Filled.Close,
contentDescription = null,
modifier = Modifier.size(28.dp),
)
}
}
)
},
content = { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
LazyColumn(contentPadding = innerPadding) {
/**
* 导航栏到title的距离
*/
item {
Spacer(modifier = Modifier.height(40.dp))
}
/**
* 手机号登陆title
*/
item {
Box(
modifier = Modifier
.height(50.dp)
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
Text(
text = "手机号登陆",
fontSize = 20.sp
)
}
}
/**
* 手机号输入框
*/
item {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 15.dp, end = 15.dp)
.wrapContentHeight(),
) {
TextField(
readOnly = true,
value = phoneText,
onValueChange = {
phoneText = it
},
colors = TextFieldDefaults.outlinedTextFieldColors(
containerColor = Color.Transparent,
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
),
textStyle = TextStyle(
fontSize = 16.sp
),
leadingIcon = {
Text(
text = "手机号",
fontSize = 18.sp,
modifier = Modifier.width(90.dp)
)
},
modifier = Modifier.fillMaxWidth(),
)}
}
/**
* 手机号底部的下划线
*/
item {
Box(modifier = Modifier.padding(start = 15.dp, end = 15.dp)) {
CQDivider(thickness = 0.5.dp)
}
}
/**
* 暗码输入框
*/
item {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 15.dp, end = 15.dp)
.wrapContentHeight(),
) {
TextField(
value = pwdText,
onValueChange = {
pwdText = it
},
colors = TextFieldDefaults.outlinedTextFieldColors(
containerColor = Color.Transparent,
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
cursorColor = Color(0xff5ECC71)
),
textStyle = TextStyle(
fontSize = 16.sp
),
leadingIcon = {
Text(
text = if (isPwdAuth) "暗码" else "验证码",
fontSize = 18.sp,
modifier = Modifier.width(90.dp)
)
},
modifier = Modifier.fillMaxWidth().onFocusChanged {
isFocus = when {
it.isFocused -> true
else -> false
}
},
placeholder = {
Text(
text = if (isPwdAuth) "请填写微信暗码" else "请填写验证码",
fontSize = 16.sp,
color = Color(0xff888888),
)
}
)}
}
item {
if (!isPwdAuth) {
Box(
modifier = Modifier
.padding(start = 110.dp, end = 15.dp, bottom = 4.dp)
.fillMaxWidth(),
contentAlignment = Alignment.CenterStart
) {
Text(
text = "获取验证码",
fontSize = 16.sp,
modifier = Modifier
.wrapContentHeight()
.wrapContentWidth()
.clip(RoundedCornerShape(8.dp))
.background(Color(0xffE1E1E1))
.padding(
start = 10.dp,
top = 2.dp,
end = 10.dp,
bottom = 6.dp
)
)
}
}
}
item {
Box(modifier = Modifier.padding(start = 15.dp, end = 15.dp)) {
CQDivider(thickness = 1.dp, colorId = if (isFocus) R.color.green else R.color.gray_10)
}
}
item {
Text(
text = if (isPwdAuth) "用短信验证码登陆" else "暗码登陆",
fontSize = 14.sp,
color = Color(0xff5F6594),
modifier = Modifier
.padding(15.dp)
.clickable {
isPwdAuth = !isPwdAuth
}
)
}
/**
* 进度框
*/
item {
if (loading.value) {
ProcessDialogComponent(
loading = loading,
content = "正在登陆..."
)
}
}
}
/**
* 底部布局(登陆按钮,找回暗码等)
*/
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.BottomCenter) {
Column(modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()) {
Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
contentAlignment = Alignment.Center
) {
Text(
text = "登陆",
fontSize = 16.sp,
color = Color.White,
modifier = Modifier
.wrapContentHeight()
.wrapContentWidth()
.clip(RoundedCornerShape(8.dp))
.background(Color(0xff5ECC71))
.padding(
top = 10.dp,
bottom = 10.dp,
start = 80.dp,
end = 80.dp
)
.clickable {
if (pwdText == "") {
context.toast(if (isPwdAuth) "请输入暗码" else "请输入验证码")
return@clickable
}
if (pwdText != "123456") {
context.toast(if (isPwdAuth) "暗码不正确" else "验证码不正确")
return@clickable
}
loading.value = true
scope.launch {
delay(2000)
loading.value = false
MainActivity.navigate(context)
}
},
textAlign = TextAlign.Center
)
}
/**
* 中心的分割线
*/
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 60.dp)
) {
Text(
text = "找回暗码",
fontSize = 16.sp,
color = Color(0xff5F6594),
modifier = Modifier
.padding(15.dp)
.weight(1f),
textAlign = TextAlign.End
)
Box(modifier = Modifier
.height(50.dp)
.width(0.5.dp)
.padding(top = 15.dp, bottom = 8.dp)
.background(Color(0xff888888))
)
Text(
text = "更多选项",
fontSize = 16.sp,
color = Color(0xff5F6594),
modifier = Modifier
.padding(15.dp)
.weight(1f),
textAlign = TextAlign.Start
)
}
}
}
}
}
)
}
}
总结
到这儿,就完成了仿微信登陆模块的首要页面了,这些页面运用了 Scaffold 脚手架,水平布局和垂直布局分别运用了 Row 和 Column 组件,滚动布局运用了 LazyColumn,输入框运用了 TextField 组件,页面跳转运用了导航组件 Navigation ,网络图片加载运用了 coil。这儿边还有一个比较生疏的是remember,它是Jetpack Compose是一个强壮的功能,用于在界面重构期间保存和康复界面状况,是一个Composable函数,用于记住Composable的内部状况,以便在界面重构时可以轻松地保存和康复界面状况,这儿边我首要运用它完成一些条件的UI切换。