Android compose wanandroid app之导航规整以及登录页个人中心页实现
Posted theyangchoi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android compose wanandroid app之导航规整以及登录页个人中心页实现相关的知识,希望对你有一定的参考价值。
导航规整并实现登录页个人中心页
前言
在前面开发时只是注重了页面绘制,已经compose各种组件的使用,没有规整导航,所以页面跳转的操作很难实现;今天先规整一下页面导航,在页面跳转操作完成之后在绘制登录页以及个人中心页。
导航规整
在前面绘制页面的时候说到,compose打开页面的时候会在当前页面直击打开,所以就需要把要打开的页面都放在主页中进行打开,那么就要区分页面是首页,还是其他页面。
首先定义一个页面枚举,main代表首页,其他则是其他页面:
/**
* 页面类
* */
enum class RouteKey(val route:String)
Main("main"),
Login("login"),
WebView("webview")
使用navhost进行导航,主页所有页面都用navigation进行包裹:
@ExperimentalMaterialApi
@ExperimentalCoilApi
@ExperimentalPagerApi
@Composable
fun RouteNavigation(navHostController: NavHostController,
onFinish: () -> Unit
)
val context = LocalContext.current
NavHost(navController = navHostController, startDestination = RouteKey.Main.route)
//主页面
navigation(
route = RouteKey.Main.route,
startDestination = Nav.BottomNavScreen.HomeScreen.route
)
composable(Nav.BottomNavScreen.HomeScreen.route)
HomePage(navHostController = navHostController)
....//其他要展示在主页面的paer
//要打开的新页面
//登录页
composable(RouteKey.Login.route)
LoginPage(navHostController = navHostController)
首页导航页面把四个页面都封装起来:
object Nav
sealed class BottomNavScreen(val route: String, @StringRes val resourceId: Int, @DrawableRes val id: Int)
object HomeScreen: BottomNavScreen("home", R.string.nav_home, R.drawable.home_unselected)
object ProjectScreen: BottomNavScreen("project",R.string.nav_project,R.drawable.project_unselected)
object ClassicScreen: BottomNavScreen("classic",R.string.nav_classic,R.drawable.classic_unselected)
object MineScreen: BottomNavScreen("mine", R.string.nav_mine, R.drawable.mine_unselected)
//主页点击两次返回桌面
var onMainBackPressed = false
val bottomNavRoute = mutableStateOf<BottomNavScreen>(BottomNavScreen.HomeScreen)
将不同页面的展示封装到一个page,所有页面都在这个page打开,并加载到MainActivity里面去,但是要区分是主页,还是其他页面。
先判断是否是主页:
fun isMainScreen(route:String):Boolean = when(route)
Nav.BottomNavScreen.HomeScreen.route,
Nav.BottomNavScreen.ProjectScreen.route,
Nav.BottomNavScreen.ClassicScreen.route,
Nav.BottomNavScreen.MineScreen.route -> true
else -> false
然后根据得到的结果加载页面:
@ExperimentalPagerApi
@ExperimentalMaterialApi
@Composable
fun MainPage(
navHostController: NavHostController = rememberNavController(),
onFinish:() -> Unit
)
//返回back堆栈的顶部条目
val navBackStackEntry by navHostController.currentBackStackEntryAsState()
//返回当前route
val currentRoute = navBackStackEntry?.destination?.route ?: Nav.BottomNavScreen.HomeScreen.route
//加载主页内容
if (isMainScreen(currentRoute))
Scaffold(
contentColor = MaterialTheme.colors.background,
//标题栏
topBar =
Column
Spacer(
modifier = Modifier
.background(MaterialTheme.colors.primary)
.statusBarsHeight()
.fillMaxWidth()
)
,
//底部导航栏
bottomBar =
Column
BottomNavBar(Nav.bottomNavRoute.value, navHostController)
Spacer(
modifier = Modifier
.background(MaterialTheme.colors.primary)
.navigationBarsHeight()
.fillMaxWidth()
)
,
//内容
content = paddingValues: PaddingValues ->
//内容嵌套在Scaffold中
RouteNavigation(navHostController, paddingValues, onFinish)
OnBackClick(navHostController)
)
else
//加载独立页面
RouteNavigation(navHostController, onFinish = onFinish)
到这里就完成了导航的规整,页面打开也没有问题,接下来就是个人中心页面以及登录页面的绘制和实现了。
个人中心的实现
目前个人中心比较简单,就展示了一个头像,昵称,用户id以及用户积分,更多的东西等到实现收藏等操作之后在添加,简单看一下效果图。
布局元素比较简单,这里就不贴布局文件了。
MineViewmodel获取数据
登录成功之后保存cookie,通过cookie调用用户信息接口,获取用户信息。
class MineViewModel : ViewModel()
//默认头像
val defaultHead = "https://jusha-info.oss-cn-shenzhen.aliyuncs.com/obt/mall/upload/image/store/2021/08/06/1628250153533.png"
private val _userInfo = MutableLiveData<UserConfigModule>()
val userInfo = _userInfo
fun getUserInfo()
Log.e("intoTAG","get user info")
NetWork.service.getUserInfo().enqueue(object : Callback<BaseResult<UserConfigModule>>
override fun onResponse(
call: Call<BaseResult<UserConfigModule>>,response: Response<BaseResult<UserConfigModule>>)
Log.e("intoTAG","response")
response.body()?.let
_userInfo.value = it.data
override fun onFailure(call: Call<BaseResult<UserConfigModule>>, t: Throwable)
Log.e("intoTAG","onFailure$t.message")
)
MinePage
获取信息并展示。
@Composable
fun MinePage(navHostController: NavHostController)
val mineViewModel:MineViewModel = viewModel()
val userInfo by mineViewModel.userInfo.observeAsState()
mineViewModel.getUserInfo()
Column(
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState()))
com.yangchoi.composeuidemo.ui.bar.TopAppBar(title = "我的")
Box(
Modifier
.background(Color.White)
.fillMaxSize()
)
Column(Modifier.fillMaxSize())
if (userInfo !== null)
//头像昵称
ConstraintLayout
val (headImg,userName,userId) = createRefs()
Image(painter = rememberImagePainter(mineViewModel.defaultHead),
contentDescription = "用户头像",
modifier = Modifier
.size(80.dp)
.padding(16.dp, 20.dp, 0.dp, 0.dp)
.clip(shape = RoundedCornerShape(50))
.constrainAs(headImg) )
Text(text = "$userInfo!!.userInfo.nickname",fontSize = 14.sp,color = Color.Black,modifier = Modifier
.padding(10.dp, 20.dp, 0.dp, 0.dp)
.constrainAs(userName)
start.linkTo(headImg.end)
top.linkTo(headImg.top)
)
Text(text = "$userInfo!!.userInfo.id",fontSize = 12.sp,color = Color.Gray,modifier = Modifier
.padding(10.dp, 20.dp, 0.dp, 0.dp)
.constrainAs(userId)
start.linkTo(headImg.end)
bottom.linkTo(headImg.bottom)
)
ConstraintLayout(modifier = Modifier
.fillMaxWidth()
.padding(vertical = 40.dp)
.height(50.dp))
val (icons,title,integral,btmLine) = createRefs()
Row(Modifier
.constrainAs(icons)
.fillMaxHeight()
.padding(16.dp, 0.dp, 0.dp, 0.dp),
verticalAlignment = Alignment.CenterVertically)
Image(painter = painterResource(id =R.drawable.icon_integral),
contentDescription = "积分", modifier = Modifier
.height(20.dp)
.width(20.dp))
Row(modifier = Modifier
.constrainAs(title)
start.linkTo(icons.end)
.fillMaxHeight()
.padding(horizontal = 10.dp),
verticalAlignment = Alignment.CenterVertically)
Text(text = "积分",fontSize = 12.sp,color = Color.Black,textAlign = TextAlign.Center)
Row(modifier = Modifier
.fillMaxHeight()
.constrainAs(integral)
end.linkTo(parent.end)
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically)
Text(text = "$userInfo!!.coinInfo.coinCount",fontSize = 12.sp,color = Color.Gray,textAlign = TextAlign.Center,)
Divider(
modifier = Modifier
.padding(0.dp, 0.dp, 16.dp, 0.dp,)
.constrainAs(btmLine)
bottom.linkTo(parent.bottom)
,
color = Color(229,224,227),
thickness = 1.dp,
startIndent = 16.dp)
else
Row(modifier = Modifier
.padding(horizontal = 16.dp, vertical = 200.dp)
.fillMaxWidth()
.height(50.dp)
.border(
1.dp,
color = Color(114, 160, 240),
shape = RoundedCornerShape(20.dp)
),verticalAlignment = Alignment.CenterVertically)
Text(text = "登 录",
fontSize = 16.sp,
modifier = Modifier
.fillMaxWidth()
.clickable
navHostController.navigate("$RouteKey.Login.route")
,
color = Color(114, 160, 240),
textAlign = TextAlign.Center)
请求头添加cookie
登录成功之后会返回一个cookie在请求头里面,只需要将cookie拦截并保存下来,就可以通过cookie去获取用户信息。
//创建OKhttp
private val client: OkHttpClient.Builder = OkHttpClient.Builder()
.addInterceptor(LogInterceptor())
.addInterceptor
val request = it.request()
val response = it.proceed(request)
val requestUrl = request.url.toString()
val domain = request.url.host
//cookie可能有多个,都保存下来
if ((requestUrl.contains(SAVE_USER_LOGIN_KEY) || requestUrl.contains(SAVE_USER_REGISTER_KEY)))
val cookies = response.headers(SET_COOKIE_KEY)
val cookie = encodeCookie(cookies)
saveCookie(requestUrl, domain, cookie)
response
//请求时设置cookie
.addInterceptor
val request = it.request()
val builder = request.newBuilder()
val domain = request.url.host
//获取domain内的cookie
if (domain.isNotEmpty())
val sqDomain: String = DataStoreUtil.readStringData(domain, "")
val cookie: String = if (sqDomain.isNotEmpty()) sqDomain else ""
if (cookie.isNotEmpty())
builder.addHeader(COOKIE_NAME, cookie)
it.proceed(builder.build())
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.retryOnConnectionFailure(false)
在网络请求的位置添加以上两个拦截器就行了。
登录页面的实现
首先来看效果图。
简单的绘制了一个登录页面,UI就不要纠结了,丑是真的丑~
可以看到在输入框左边有一个图标,然后是提示内容,以及密码框右边的显示和隐藏密码的图标;选中的时候颜色发生改变,并且在左上角显示提示用户输入的内容。
OutlinedTextField 属性解析
在实现以上效果前,先要了解OutlinedTextField的属性,才能加以运用 ;先看一下属性列表。
@Composable
fun OutlinedTextField(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
textStyle: TextStyle = LocalTextStyle.current,
label: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,<以上是关于Android compose wanandroid app之导航规整以及登录页个人中心页实现的主要内容,如果未能解决你的问题,请参考以下文章
Android Kotlin Jetpack Compose 使用