通过 git clone https://github.com/googlecodelabs/android-compose-codelabs
克隆代码,打开 BasicLayoutCodelab 项目,首先,布局分为上下两部分:
其次,上半部分又细分为如下三个模块:
// Step: Search bar - Modifiers
@Composable
fun SearchBar(
modifier: Modifier = Modifier
) {
TextField(
value = "",
onValueChange = {},
leadingIcon = {
Icon(
imageVector = Icons.Default.Search,
contentDescription = null,
)
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = MaterialTheme.colors.surface
),
placeholder = {
Text(stringResource(R.string.placeholder_search))
},
modifier = modifier
.fillMaxWidth()
.heightIn(min = 56.dp)
)
}
效果如下:
接下来,您要实现的可组合项是“Align your body”元素。我们来看看该元素的设计,包括它旁边的红线设计:
代码实现如下:
@Preview(showBackground = true, backgroundColor = 0xFFF0EAE2)
@Composable
fun AlignYourBodyElementPreview() {
MySootheTheme {
AlignYourBodyElement(
drawable = R.drawable.ab1_inversions,
text = R.string.ab1_inversions,
modifier = Modifier.padding(8.dp),
)
}
}
// Step: Align your body - Alignment
@Composable
fun AlignYourBodyElement(
@DrawableRes drawable: Int,
@StringRes text: Int,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(drawable),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.size(88.dp)
.clip(CircleShape)
)
Text(
text = stringResource(text),
style = MaterialTheme.typography.h3,
modifier = Modifier.paddingFromBaseline(
top = 24.dp, bottom = 8.dp
)
)
}
}
预览效果如下:
接下来,设计矩形卡片,效果图如下:
代码如下:
// Step: Favorite collection card - Material Surface
@Composable
fun FavoriteCollectionCard(
modifier: Modifier = Modifier
) {
Surface(shape = MaterialTheme.shapes.small, modifier = modifier) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.width(192.dp)
) {
Image(
painter = painterResource(R.drawable.fc2_nature_meditations),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.size(56.dp)
)
Text(
text = stringResource(R.string.fc2_nature_meditations),
style = MaterialTheme.typography.h3,
modifier = Modifier.padding(horizontal = 16.dp)
)
}
}
}
预览效果如下:
现在已经创建了屏幕上显示的基本可组合项,接下来可以实现横向列表了,布局如下:
每个网格是 8dp,所以第一项和最后一项距边缘为 16dp,各图之间为 8dp,代码如下:
// Step: Align your body row - Arrangements
@Composable
fun AlignYourBodyRow(
modifier: Modifier = Modifier
) {
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(horizontal = 16.dp),
modifier = modifier
) {
items(alignYourBodyData) { item ->
AlignYourBodyElement(item.drawable, item.text)
}
}
}
预览后,效果如下:
接下来要实现的是 Grid,而不是上文的 Row。
// Step: Favorite collections grid - LazyGrid
@Composable
fun FavoriteCollectionsGrid(
modifier: Modifier = Modifier
) {
LazyHorizontalGrid(
rows = GridCells.Fixed(2),
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier.height(120.dp)
) {
items(favoriteCollectionsData) { item ->
FavoriteCollectionCard(
drawable = item.drawable,
text = item.text,
modifier = Modifier.height(56.dp)
)
}
}
}
// Step: Favorite collection card - Material Surface
@Composable
fun FavoriteCollectionCard(
modifier: Modifier = Modifier,
@DrawableRes drawable: Int,
@StringRes text: Int
) {
Surface(shape = MaterialTheme.shapes.small, modifier = modifier) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.width(192.dp)
) {
Image(
painter = painterResource(drawable),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.size(56.dp)
)
Text(
text = stringResource(text),
style = MaterialTheme.typography.h3,
modifier = Modifier.padding(horizontal = 16.dp)
)
}
}
}
预览后,效果如下:
在 MySoothe 主屏幕中,有多个版块都遵循同一模式。每个版块都有一个标题,其中包含的内容因版块而异。我们想要实现的设计如下所示:
因为每个板块,都有一个标题,一个槽位。标题包含一些与其相关的间距和样式信息。可以使用不同的内容动态填充槽位,具体取决于版块。如需实现这个灵活的版块容器,可以用槽位 API,代码如下:
// Step: Home section - Slot APIs
@Composable
fun HomeSection(
@StringRes title: Int,
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
Column(modifier) {
Text(stringResource(title))
content()
}
}
@Preview(showBackground = true, backgroundColor = 0xFFF0EAE2)
@Composable
fun HomeSectionPreview() {
MySootheTheme {
HomeSection(R.string.align_your_body) {
AlignYourBodyRow()
}
}
}
效果如下:
现在,已经创建了所有单独的构建块,接下来可以将它们组合成一个全屏实现了,效果如下:
代码如下:
@Preview(showBackground = true, backgroundColor = 0xFFF0EAE2)
@Composable
fun BottomNavigationPreview() {
MySootheTheme { SootheBottomNavigation(Modifier.padding(top = 24.dp)) }
}
// Step: Home screen - Scrolling
@Composable
fun HomeScreen(modifier: Modifier = Modifier) {
Column(
modifier
.verticalScroll(rememberScrollState())
.padding(vertical = 16.dp)
) {
SearchBar(Modifier.padding(horizontal = 16.dp))
HomeSection(title = R.string.align_your_body) {
AlignYourBodyRow()
}
HomeSection(title = R.string.favorite_collections) {
FavoriteCollectionsGrid()
}
}
}
效果如下:
// Step: Bottom navigation - Material
@Composable
private fun SootheBottomNavigation(modifier: Modifier = Modifier) {
BottomNavigation(modifier, backgroundColor = MaterialTheme.colors.background) {
BottomNavigationItem(
icon = {
Icon(
imageVector = Icons.Default.Spa,
contentDescription = null,
)
},
label = {
Text(stringResource(R.string.bottom_navigation_home))
},
selected = true,
onClick = {}
)
BottomNavigationItem(
icon = {
Icon(imageVector = Icons.Default.AccountCircle, contentDescription = null)
},
label = {
Text(stringResource(R.string.bottom_navigation_profile))
},
selected = false,
onClick = {}
)
}
}
效果如下:
// Step: MySoothe App - Scaffold
@Composable
fun MySootheApp() {
MySootheTheme {
Scaffold(bottomBar = { SootheBottomNavigation() }) { padding ->
HomeScreen(Modifier.padding(padding))
}
}
}
整体 App 效果如下: