背景
还在为Dark Mode
、RTL Mode
所苦恼吗?快来试试Jetpack Compose
!一键切换,提升幸福指数。一起来学习酷炫的Jetpack Compose
吧
预览
设计
TitleBar
经典三段式,Back Icon
,Setting Icon
,Title Text
,由settingDialogState
来记录设置弹窗的状态:
TopAppBar(
backgroundColor = MaterialTheme.colors.background,
contentPadding = PaddingValues(start = 18.dp, end = 18.dp)
) {
Icon(
painter = rememberVectorPainter(image = Icons.Default.ArrowBack),
contentDescription = "back",
modifier = Modifier.size(24.dp)
)
Text(
text = "橱窗列表",
fontSize = TextUnit(17f, TextUnitType.Sp),
fontWeight = FontWeight(700),
textAlign = TextAlign.Center,
modifier = Modifier.weight(1f)
)
Icon(
painter = rememberVectorPainter(image = Icons.Default.Settings),
contentDescription = "setting",
modifier = Modifier
.size(24.dp)
.clickable {
settingDialogState.value = true
}
)
}
复制代码
预览效果 |
---|
![]() |
商品
图片文字组合在一起,不是特别复杂的布局使用Row
和Column
混搭即可:
Row(modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp)) {
Image(
painter = rememberGlidePainter(product.url),
contentDescription = "product image",
contentScale = ContentScale.FillBounds,
modifier = Modifier
.size(108.dp, 108.dp)
.clip(RoundedCornerShape(2.dp)),
)
Column(
modifier = Modifier
.padding(start = 12.dp)
.requiredHeight(108.dp)
.fillMaxWidth()
) {
Text(
text = product.name,
fontSize = TextUnit(15f, TextUnitType.Sp),
fontWeight = FontWeight(500),
maxLines = 2
)
Text(
text = product.price,
fontWeight = FontWeight(600),
fontSize = TextUnit(15f, TextUnitType.Sp),
modifier = Modifier.padding(top = 4.dp)
)
Text(
text = product.origin,
fontWeight = FontWeight(300),
fontSize = TextUnit(13f, TextUnitType.Sp),
modifier = Modifier.padding(top = 4.dp)
)
Spacer(modifier = Modifier.weight(1f))
RedButton(
text = if (product.added) "Added" else "Add",
modifier = Modifier
.align(Alignment.End)
.clickable {
if (!product.added) {
product.added = true
addBtnClick(product.id)
}
},
isDark = isDarkMode,
isAdded = product.added
)
}
}
复制代码
预览效果 |
---|
![]() |
关键的来了,这个按钮有两种状态:Add
和Added
:
Add | Added |
---|---|
![]() |
![]() |
这个在数据里应该如何表示呢?我们知道Jetpack Compose
的UI是由State
驱动的,因此我们也要使用State
去定义这个字段:
data class ProductBean(
val id: Int,
val url: String,
val name: String,
val price: String,
val origin: String
) {
var added by mutableStateOf(false)
}
复制代码
这样则在added
字段变更时修改按钮颜色。
字段定义好之后又该如何设计UI呢?按钮仅有两个部分,背景和文字,那么只需要分别控制它们的颜色即可,但又要考虑到暗黑模式,所以算是有4种样式:
class RedButtonColorDelegate(private val isDark: Boolean, private val isAdded: Boolean) {
val btnColor: Color = if (isAdded) {
btnColorAdded
} else {
btnColorAdd
}
val textColor: Color = if (isAdded) {
textColorAdded
} else {
textColorAdd
}
private val btnColorAdd: Color
get() = Color(0xFFFE2C55)
private val textColorAdd: Color
get() = Color.White
//added
private val btnColorAdded: Color
get() =
if (isDark) {
Color(0x14FFFFFF)
} else {
Color(0xF161823)
}
private val textColorAdded: Color
get() =
if (isDark) {
Color(0x57FFFFFF)
} else {
Color(0x57161823)
}
}
复制代码
定义好颜色之后我们只需要根据状态取颜色即可:
@Composable
fun RedButton(
modifier: Modifier = Modifier,
text: String,
isAdded: Boolean = false,
isDark: Boolean = false
) {
Box(
modifier = modifier
.size(height = 28.dp, width = 88.dp)
.clip(RoundedCornerShape(2.dp))
.background(
color = RedButtonColorDelegate(
isDark = isDark,
isAdded = isAdded
).btnColor
)
) {
Text(
text = text,
color = RedButtonColorDelegate(
isDark = isDark,
isAdded = isAdded
).textColor,
fontSize = TextUnit(14f, TextUnitType.Sp),
fontWeight = FontWeight(600),
textAlign = TextAlign.Center,
modifier = Modifier
.align(Alignment.Center)
.padding(start = 8.dp, end = 8.dp)
)
}
}
复制代码
长列表
Jetpack Compose
长列表实在是太简单啦,再也不用写Adapter啦:
LazyColumn(modifier = Modifier
.weight(1f)
.fillSize()) {
items(items = products, key = { it.id }) {
ProductItem(product = it, isDarkMode =false, productClick)
}
}
复制代码
弹窗
在Jetpack Compose
里我们可以使用ModalBottomSheetLayout
来实现底部弹窗,非常简单:
val scope = rememberCoroutineScope()
val addMenuState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
ModalBottomSheetLayout(
sheetState = addMenuState,
sheetShape = RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp),
sheetContent = {
//弹窗内容
AddMenu { scope.launch { addMenuState.hide() } }
}
) {
...
}
复制代码
预览效果 |
---|
![]() |
DarkMode
使用Jetpack Compose
切换Dark Mode
更是简单不过,我们可以使用MaterialDesign提供的MaterialTheme
,也可以完全自定义。
//定义颜色
private val DarkColorPalette = darkColors(
primary = Purple200,
primaryVariant = Purple700,
secondary = Teal200
)
private val LightColorPalette = lightColors(
primary = Purple500,
primaryVariant = Purple700,
secondary = Teal200
}
//定义主题
@Composable
fun ManageShowCaseComposeTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable() () -> Unit
) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
}
//使用此主题:
ManageShowCaseComposeTheme(darkTheme = viewModel.darkModeState.value){
TitileBar()
...
}
复制代码
标题 |
---|
![]() |
RTL
有些产品面向阿拉伯地区,需要RTL Mode
,这个功能Compose
也为我们准备好了:
我们只需要在我们需要RTL
的视图外层使用 CompositionLocalProvider
即可,这里简单理解为这个一个依赖注入能力,此视图之下的子Compose
拿对应的数据,比如这里是LocalLayoutDirection
,都是同一个实例。布局时会根据LocalLayoutDirection
来进行排版。
CompositionLocalProvider(LocalLayoutDirection provides if (rtlState.value) LayoutDirection.Rtl else LayoutDirection.Ltr) {
TitileBar()
...
}
复制代码
注意:目前LocalLayoutDirection
仅是对布局进行翻转,对组件内容并没镜像,如果想要图片翻转可能还需要进行一些工作。
预览 |
---|
![]() |
总结
是不是非常简单?Jetpack Compose
即将发布Release
版本,赶紧学习起来~~
代码示例已传至Github: github.com/Palardin3/C…