已解决
《Jetpack Compose从入门到实战》第三章 定制 UI 视图
来自网友在路上 164864提问 提问时间:2023-10-02 07:40:12阅读次数: 64
最佳答案 问答题库648位专家为你答疑解惑
目录
- 配置颜色、字体与形状
- Welcome Page
- Login Page
- Home Page
- 主题
- CompositionLocal
配置颜色、字体与形状
-ui.theme.Color.kt
val pink100 = Color(0xFFFFF1F1)
val pink900 = Color(0xFF3F2C2C)
val white = Color(0xFFFFFFFF)
val white850 = Color(0xD9FFFFFF)
val gray = Color(0xFF232323)
- ui.theme.Type.kt
先将Nunito Sans字体家族放入 res/font,再根据设计稿写代码
val nunitoSansFamily = FontFamily(Font(R.font.nunitosans_light, FontWeight.Light),Font(R.font.nunitosans_semibold, FontWeight.SemiBold),Font(R.font.nunitosans_bold, FontWeight.Bold)
)val h1 = TextStyle(fontSize = 18.sp,fontFamily = nunitoSansFamily,fontWeight = FontWeight.Bold
)
val h2 = TextStyle(fontSize = 14.sp,letterSpacing = 0.15.sp,fontFamily = nunitoSansFamily,fontWeight = FontWeight.Bold
)
val subtitle1 = TextStyle(fontSize = 16.sp,fontFamily = nunitoSansFamily,fontWeight = FontWeight.Light
)
val body1 = TextStyle(fontSize = 14.sp,fontFamily = nunitoSansFamily,fontWeight = FontWeight.Light
)
val body2 = TextStyle(fontSize = 12.sp,fontFamily = nunitoSansFamily,fontWeight = FontWeight.Light
)
val button = TextStyle(fontSize = 14.sp,letterSpacing = 1.sp,fontFamily = nunitoSansFamily,fontWeight = FontWeight.SemiBold,color = white
)
val caption = TextStyle(fontSize = 12.sp,fontFamily = nunitoSansFamily,fontWeight = FontWeight.SemiBold
)
- ui.theme/Shape.kt
Welcome Page
@Preview(showBackground = true)
@Composable
fun WelcomeTitle() {Column(horizontalAlignment = Alignment.CenterHorizontally,modifier = Modifier.fillMaxWidth()) {Image(painter = rememberVectorPainter(image = ImageVector.vectorResource(id = R.drawable.ic_light_logo)),contentDescription = "weclome_logo",modifier = Modifier.wrapContentWidth().height(32.dp))Box(modifier = Modifier.fillMaxWidth().height(32.dp),contentAlignment = Alignment.BottomCenter) {Text(text = "Beautiful home garden solutions",textAlign = TextAlign.Center,style = subtitle1,color = gray)}}
}@Preview(showBackground = true)
@Composable
fun WelcomeButtons() {Column(horizontalAlignment = Alignment.CenterHorizontally,modifier = Modifier.fillMaxWidth()){Button(onClick = { },modifier = Modifier.height(48.dp).padding(horizontal = 16.dp).fillMaxWidth().clip(medium),colors = ButtonDefaults.buttonColors(backgroundColor = pink900)) {Text(text = "Create account",style = button,color = white)}Spacer(modifier = Modifier.height(24.dp))TextButton(onClick = { },) {Text(text = "Log in",style = button,color = pink900,)}}
}@Preview(showBackground = true)
@Composable
fun LeafImage() {Image(painter = rememberVectorPainter(image = ImageVector.vectorResource(id = R.drawable.ic_light_welcome_illos)),contentDescription = "weclome_illos",modifier = Modifier.wrapContentSize().padding(start = 88.dp))
}@Preview(showBackground = true)
@Composable
fun WelcomeContent() {Column(modifier = Modifier.fillMaxSize()) {Spacer(Modifier.height(72.dp))LeafImage()Spacer(modifier = Modifier.height(48.dp))WelcomeTitle()Spacer(modifier = Modifier.height(40.dp))WelcomeButtons()}
}@Composable
fun WelcomePage() {Box(modifier = Modifier.fillMaxSize().background(pink100)) {Image(painter = rememberVectorPainter(image = ImageVector.vectorResource(id = R.drawable.ic_light_welcome_bg)),contentDescription = "weclome_bg",modifier = Modifier.fillMaxSize())WelcomeContent()}
}
Login Page
@Preview(showBackground = true)
@Composable
fun TopText() {Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween) {var keywordPre = "By Clicking below you agree to our".split(" ")var keywordPost = "and consent".split(" ")for (word in keywordPre) {Text(text = word,style = body2,color = gray,)}Text(text = "Terms of Use",style = body2,color = gray,textDecoration = TextDecoration.Underline)for (word in keywordPost) {Text(text = word,style = body2,color = gray,)}}
}@Preview(showBackground = true)
@Composable
fun BottomText() {Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) {Text(text = " to Our ",style = body2,color = gray)Text(text = "Privacy Policy.",style = body2,color = gray,textDecoration = TextDecoration.Underline)}
}@Preview(showBackground = true)
@Composable
fun HintWithUnderline() {Column(modifier = Modifier.paddingFromBaseline(top = 24.dp, bottom = 16.dp)){TopText()BottomText()}
}@Preview(showBackground = true)
@Composable
fun LoginInputBox() {Column {OutlinedTextField(value = "",onValueChange = {},modifier = Modifier.fillMaxWidth().height(56.dp).clip(small),placeholder = {Text(text = "Email address",style = body1,color = gray)})Spacer(modifier = Modifier.height(8.dp))OutlinedTextField(value = "",onValueChange = {},modifier = Modifier.fillMaxWidth().height(56.dp).clip(small),placeholder = {Text(text = "Password(8+ Characters)",style = body1,color = gray)})}
}@Preview(showBackground = true, showSystemUi = false)
@Composable
fun LoginTitle() {Text(text = "Log in with email",modifier = Modifier.fillMaxWidth().paddingFromBaseline(top = 184.dp, bottom = 16.dp),style = h1,color = gray,textAlign = TextAlign.Center)
}@Preview(showBackground = true)
@Composable
fun LoginButton() {Button(onClick = { },modifier = Modifier.height(48.dp).fillMaxWidth().clip(medium),colors = ButtonDefaults.buttonColors(backgroundColor = pink900)) {Text(text = "Log in",style = button,color = white)}
}@Composable
fun LoginPage() {Column(Modifier.fillMaxSize().background(white).padding(horizontal = 16.dp)) {LoginTitle()LoginInputBox()HintWithUnderline()LoginButton()}
}@Composable
@Preview
fun LoginPageLightPreview() {BloomTheme() {LoginPage()}
}
Home Page
val small = RoundedCornerShape(4.dp)
val medium = RoundedCornerShape(24.dp)val shapes = Shapes(small = RoundedCornerShape(4.dp),medium = RoundedCornerShape(4.dp),large = RoundedCornerShape(0.dp)
)
data class ImageItem(val name: String, val resId: Int)val bloomBannerList = listOf(ImageItem("Desert chic", R.drawable.desert_chic),ImageItem("Tiny terrariums", R.drawable.tiny_terrariums),ImageItem("Jungle Vibes", R.drawable.jungle_vibes)
)val bloomInfoList = listOf(ImageItem("Monstera", R.drawable.monstera),ImageItem("Aglaonema", R.drawable.aglaonema),ImageItem("Peace lily", R.drawable.peace_lily),ImageItem("Fiddle leaf tree", R.drawable.fiddle_leaf),ImageItem("Desert chic", R.drawable.desert_chic),ImageItem("Tiny terrariums", R.drawable.tiny_terrariums),ImageItem("Jungle Vibes", R.drawable.jungle_vibes)
)val navList = listOf(ImageItem("Home", R.drawable.ic_home),ImageItem("Favorites", R.drawable.ic_favorite_border),ImageItem("Profile", R.drawable.ic_account_circle),ImageItem("Cart", R.drawable.ic_shopping_cart)
)@Preview(showBackground = true)
@Composable
fun BloomRowBanner() {Column {Box(Modifier.fillMaxWidth()) {Text(text = "Browse themes",style = h1,color = gray,modifier = Modifier.fillMaxWidth().paddingFromBaseline(top = 32.dp))}Spacer(modifier = Modifier.height(16.dp))LazyRow(modifier = Modifier.height(136.dp)) {items(bloomBannerList.size) {if (it != 0) {Spacer(modifier = Modifier.width(8.dp))}PlantCard(bloomBannerList[it])}}}
}@Preview(showBackground = true)
@Composable
fun BloomInfoList() {Column {Row(Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween) {Text(text = "Design your home garden",style = h1,color = gray,modifier = Modifier.paddingFromBaseline(top = 40.dp))Icon(painterResource(id = R.drawable.ic_filter_list),"filter",modifier = Modifier.padding(top = 24.dp).size(24.dp))}Spacer(modifier = Modifier.height(16.dp))LazyColumn(modifier = Modifier.fillMaxWidth(),contentPadding = PaddingValues(bottom = 56.dp)) {items(bloomInfoList.size) {if (it != 0) {Spacer(modifier = Modifier.height(8.dp))}DesignCard(bloomInfoList[it])}}}
}@Preview(showBackground = true)
@Composable
fun SearchBar() {Box {TextField(value = "",onValueChange = {},modifier = Modifier.fillMaxWidth().height(56.dp).clip(RoundedCornerShape(4.dp)).border(BorderStroke(1.dp, Color.Black)),leadingIcon = {Icon(painter = rememberVectorPainter(image = ImageVector.vectorResource(id = R.drawable.ic_search)),contentDescription = "search",modifier = Modifier.size(18.dp))},placeholder = {Text(text = "Search",style = body1,color = gray)},colors = TextFieldDefaults.outlinedTextFieldColors(backgroundColor = white,unfocusedBorderColor = white,focusedBorderColor = white,),)}
}@Composable
fun HomePage() {Scaffold(bottomBar = {BottomBar()}) {Column(Modifier.fillMaxSize().background(white).padding(horizontal = 16.dp)) {Spacer(modifier = Modifier.height(40.dp))SearchBar()BloomRowBanner()BloomInfoList()}}
}@Composable
fun DesignCard(plant: ImageItem) {Row(modifier = Modifier.fillMaxWidth()) {Image(painterResource(id = plant.resId),contentScale = ContentScale.Crop,contentDescription = "image",modifier = Modifier.size(64.dp).clip(RoundedCornerShape(4.dp)))Spacer(modifier = Modifier.width(16.dp))Column {Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {Column {Text(text = plant.name,style = h2,color = gray,modifier = Modifier.paddingFromBaseline(top = 24.dp))Text(text = "This is a description",style = body1,color = gray,modifier = Modifier)}Checkbox(modifier = Modifier.padding(top = 24.dp).size(24.dp),checked = false,onCheckedChange = {// plant.enable = it},colors = CheckboxDefaults.colors(checkmarkColor = white))}Divider(color = gray, modifier = Modifier.padding(top = 16.dp), thickness = 0.5.dp)}}
}@Composable
fun PlantCard(plant: ImageItem) {Card(modifier = Modifier.size(136.dp).clip(RoundedCornerShape(4.dp))) {Column {Image(painterResource(id = plant.resId),contentScale = ContentScale.Crop,contentDescription = "image",modifier = Modifier.fillMaxWidth().height(96.dp))Box(Modifier.fillMaxWidth().padding(start = 16.dp)) {Text(text = plant.name,style = h2,color = gray,modifier = Modifier.fillMaxWidth().paddingFromBaseline(top = 24.dp, bottom = 16.dp))}}}
}@Composable
fun BottomBar() {BottomNavigation(elevation = 16.dp,modifier = Modifier.fillMaxWidth().height(56.dp).background(pink100)) {navList.forEach {BottomNavigationItem(onClick = {},icon = {Icon(painterResource(id = it.resId),contentDescription = null,modifier = Modifier.size(24.dp),)},label = {Text(it.name,style = caption,color = gray,)},selected = ("Home" == it.name))}}
}@Preview(showBackground = true)
@Composable
fun BottomBarPreview() {BloomTheme() {BottomBar()}
}@Preview(showBackground = true)
@Composable
fun DesignCardPreview() {BloomTheme() {DesignCard(bloomInfoList[0])}
}@Preview(showBackground = true)
@Composable
fun PlantCardPreview() {BloomTheme() {PlantCard(bloomBannerList[0])}
}@Preview(showBackground = true)
@Composable
fun HomePageLightPreview() {BloomTheme() {HomePage()}
}
主题
private val BloomLightColorPaltte = lightColors(primary = pink100,secondary = pink900,background = white,surface = white850,onPrimary = gray,onSecondary = white,onBackground = gray,onSurface = gray,
)private val BloomDarkColorPaltte = darkColors(primary = green900,secondary = green300,background = gray,surface = white150,onPrimary = white,onSecondary = gray,onBackground = white,onSurface = white850
)open class WelcomeAssets private constructor(var background: Int,var illos: Int,var logo: Int
) {object LightWelcomeAssets : WelcomeAssets(background = R.drawable.ic_light_welcome_bg,illos = R.drawable.ic_light_welcome_illos,logo = R.drawable.ic_light_logo)object DarkWelcomeAssets : WelcomeAssets(background = R.drawable.ic_dark_welcome_bg,illos = R.drawable.ic_dark_welcome_illos,logo = R.drawable.ic_dark_logo)
}internal var LocalWelcomeAssets = staticCompositionLocalOf { WelcomeAssets.LightWelcomeAssets as WelcomeAssets }val MaterialTheme.welcomeAssets@Composable@ReadOnlyComposableget() = LocalWelcomeAssets.currentenum class BloomTheme {LIGHT, DARK
}@Composable
fun BloomTheme(theme: BloomTheme = BloomTheme.LIGHT, content: @Composable() () -> Unit) {CompositionLocalProvider(LocalWelcomeAssets provides if (theme == BloomTheme.DARK) WelcomeAssets.DarkWelcomeAssets else WelcomeAssets.LightWelcomeAssets,) {MaterialTheme(colors = if (theme == BloomTheme.DARK) BloomDarkColorPaltte else BloomLightColorPaltte,typography = bloomTypoGraphy,shapes = shapes,content = content)}
}
CompositionLocal
CompositionLocal 是 Jetpack Compose 中的一种数据传递方式。它可以在组合组件之间传递可变数据,而无需通过 props 或 state 管理器来传递数据。这个特性比传统的数据传递方式更为高效和方便。
例如,我们可以通过 CompositionLocal 在应用程序的不同部分中传递数据,如主题、语言环境、字体等。这个特性可以让我们在组合应用程序中更轻松地使用全局状态,而不必每次都传递数据。
此外,CompositionLocal 还可以用于实现本地化和自定义主题等功能的高效性。因此,它是 Jetpack Compose 中非常重要的一个组成部分。
- 如果CompositonLocal提供得知发生更改的可能性很小或永远无法改变,利用staticCompositionLocal能显著提升性能
总结
- 所有视图组件建议用顶级函数声明
随笔:
- 简历 遇到什么问题,用了什么方法,如何进行优化
《Jetpack Compose从入门到实战》第一章 全新的 Android UI 框架
《Jetpack Compose从入门到实战》 第二章 了解常用UI组件
查看全文
99%的人还看了
相似问题
猜你感兴趣
版权申明
本文"《Jetpack Compose从入门到实战》第三章 定制 UI 视图":http://eshow365.cn/6-15762-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!