Jetpack Compose(第四趴)——Compose中的基本布局(下)

6、“Align your body”行 – 排列

现在,您已经创建了屏幕上显示的节本可组合项,接下来可以创建屏幕的不同不同部分了。

先从”Align your body”可滚动着手。

333.gif
此组件的红线设计如下所示:

image.png

请注意,一个网格块代表8dp。因此,在此设计中,该行中的第一项内容和最后一项内容留有16dp的间距。各项呢绒之间的间距为8dp。

在Compose中,您可以使用LazyRow可组合项实现这种可滚动行。了解LazyRow只会渲染屏幕上显示的元素(而不是同时渲染所有元素)这足够了,这有助于让应用保持出色的性能。

先从此LazyRow的基本实现着手:

import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items


@Composable
fun AlignYourBodyRow(
    modifier: Modifier = Modifier
) {
    LazyRow(
        modifier = modifier

    ) {

        items(alignYourBodyData) { item ->

            AlignYourBodyElement(item.drawable, item.text)

        }

    }

}

如您所见,LazyRow的子项不是可组合项。您应该用延迟列表DSL,它可提供itemitems等方法,这些方法会以列表项的形式发出可组合项。对于所提供的alignYourBodyData中的各项,您可以发出之前实现的AlignYourBodyElement可组合项。

请注意显示方式:

image.png

我们在红线设计中看到的间距仍未显示。若要实现这些部分,您必须了解排列方式

在上一步中,您了解了对其方式,它用于在交叉轴上对其容器的子项。对于Column,交叉轴是水平轴;对于Row,交叉轴则是垂直轴。

不过,我们也可以决定如何在容器的主轴(对于Row,是水平轴;对于Column,是垂直轴)上防止可组合项。

对于Row,您可以选择以下排列方式:

121.gif
对于Column:

122.gif

除了这些排列方式之外,您还可以使用Arrangement.spaceBy()方法,在每个可组合项之间添加固定间距。

在此示例中,您需要使用spaceBy方法,因为您需要在LazyRow中的各项之间留出8dp的间距。

import androidx.compose.foundation.layout.Arrangement



@Composable

fun AlighYourBodyRow(
    modifier: Modifier = Modifier
) {

    LazyRow(
        horizontalArrangement = Arrangement.spaceBy(8.dp),
        modifier = modifier

    ) {

        items(alignYourBodyData) { item ->

            AlignYourBodyElement(item.drawable, item.text)

        }

    }

}

现在,设计如下所示:

image.png
此外,您需要在LazyRow两侧添加一定尺寸的内边距。在此示例中,添加一个简单的内部安居修饰符并不能达到目的。请尝试向LazyRow添加内边距,看看其行为方式:

23.gif

如您所见,滚动时,第一个和最后一个可见项在屏幕两侧被截断。

为了保持相同的内边距,同时确保在父级列表的边界内滚动时内容不会被截断,所有列表都需提供一个名为contentPadding的形参。

@Composable

fun AlignYourBodyRow(
    modifier: Modifier = Modifier
) {

    LazyRow(
        horizontalArrangement = Arrangement.spaceBy(8.dp),
        contentPadding = PaddingValues(horizontal = 16.dp),
        modifier = modifier
    ) {

        items(alignYourBodyData) { item ->
            AlignYourBodyElement(item.drawable, item.text)
        }
    }

}

7、“Favorite collections”网格 – 延迟网络

接下来,您要实现的是屏幕的”Favorite collections”板块。这个可组合项需要的是网格,而不是单个行:

24.gif

您可以按照与上一部分类似的方式实现此模块,具体方法是创建一个LazyRow,让各项都包含一个具有两个FavoriteCollectionCard实例的Column。但在此步骤中,您需要使用LazyHorizontalGrid,以便更好地将各项映射到网络元素。

首先实现包含两个固定行的简单网络:

import androidx.compose.foundation.lazy.grif.GirdCells
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
import androidx.compose.foundation.lazy.grid.items

@Composable
fun FavoriteCollectionsGrid(
    modifier: Modifier = Modifier
) {

    LazyHorizontalGrid(
        rows = GridCells.Fixed(2),
        modifier = modifier
    ) {
        items(favoriteCollectionsData) { item ->
            FavoriteCollectionCard(item.drawable, item.text)
        }
    }
}

如您所见,只需将上一步中的LazyRow替换为LazyHorizontalGrid即可。

LazyHorizontalGrid是Jetpack Compose 1.2.0-alpha05中发布的延迟布局API的一部分。使用此网格时,您至少需要使用此版本。

不过,这样还无法得到正确的结果:

image.png

网格占用的空间与其父项相同,这意味着, “favorite collection”卡片会在垂直方向上被过度拉伸。调整可组合项,以便网格单元的大小以及各单元之间的间距正确无误。

结果应如下所示:

@Composable

fun FavoriteCollectionsGrid(
    modifier: Modifier = Modifier
) {

    LazyHorizontalGrid(
        rows = GridCells.Fixed(2),
        contentPadding = PaddingValues(horizontal = 16.dp),
        horizontalArrangement = Arrangement.spaceBy(8.dp),
        verticalArrangement = Arrangement.spaceBy(8.dp),
        modifier = modifier.height(120.dp)
    ) {
        items(favoriteCollectionsData) { item ->
            FavoriteCollectionCard(
                drawable = item.drawable,
                text = item.text,
                modifier = Modifier.height(56.dp)
            )
        }
    }

}

8、首页部分 – 槽位API

在MySoothe主屏幕中,有多个板块都遵循统一模式。每个板块都有一个标题,其中包含的内容因板块而异。我们想要实现的设计如下所示:

image.png

如您所见,每个版块都有一个标题和一个槽位。标题包含一些与其相关的间距和样式信息。可以使用不同的内容填充槽位,具体取决于板块。

调整HomeSection可组合项以接收标题和槽位内容。您还应调整关联的预览,以调用这个包含“Align your body”标题及相关内容的HomeSection

@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()
        }
    }
}

您可以为可组合项的槽位使用content形参。这样一来,当您使用HomeSection可组合项时,便可使用尾随lambda填充内容槽位。当可组合项提供多个要填充的槽位时,您可为这些槽位指定有意义的名称,用于在更大的可组合项容器中代表其功能。例如,Material的TopAppBartitlenavigationIconactions提供槽位。

我们来看一下这个板块采用该实现后的效果:

image.png

Text可组合项需要更多信息才能与设计保持一致。更新该可组合项,以便它:

  • 采用全部大写的形式显示(提示:您可以使用Stringuppercase()方法实现此目的)。
  • 采用H2排版。
  • 留有契合红线设计的内边距。

您的最终解决方案应如下所示:

import java.util.*



@Composable
fun HomeSection(
    String title: Int,
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {

    Column(modifier) {
        Text(
            text = stringResource(title).uppercase(Locale.getDefault()),
            style = MaterialTheme.typography.h2,
            modifier = Modifier
                .paddingFromBaseline(top = 40.dp, bottom = 8.dp)
                .padding(horizontal = 16.dp)
        )
        content()
    }
}

9、 主屏幕 – 滚动

现在,您已经创建了所有单独的构建块,接下来可以将它们组合成一个全屏实现了。

您尝试实现的设计如下所示:

image.png

只需依序放置搜索栏和这两个板块。您需要添加一定尺寸的间距,以确保一切都契合设计。我们之前没有使用过Spacer和组合项,它可帮助我们在Column中添加额外的间距。如果您改为设置Column的内边距,便会看到之前”Favorite Collections”网格中出现的相同截断行为。

@Composable

fun HomeScreen(modifier: Modifier = Modifier) {
    Column(modifier) {
        Spacer(Modifier.height(16.dp))
        SearchBar(Modifier.padding(horizontal = 16.dp))
        HomeSection(title = R.string.align_your_body) {
            AlignYourBodyRow()
        }
        HomeSection(title = R.string.favorite_collections) {
            FavoriteCollectionsGrid()
        }
        Spacer(Modifier.height(16.dp))
    }

}

虽然设计与大多数设备尺寸都非常契合,但如果设备的高度不足(例如在横屏模式下),设计需要能够垂直滚动。这就需要您添加滚动行为。

如前所述,LazyRowLazyHorizontalGrid等延迟布局会自动添加滚动行为。但是,您不一定总是需要延迟布局。一般来说,在列表中有许多元素或需要加载大型数据集时,您需要使用延迟布局,因此一次发出所有项不仅会降低性能,还会拖慢应用的运行速度。如果列表中的元素数量有限,您也可以选择使用简单的ColumnRow,然后手动添加滚动行为。因此,您可以使用verticalScrollhorizontalScroll修饰符。这些修饰符需要ScrollState,后者包含当前的滚动状态,可用于从外部修改滚动状态。在此示例中,您不需要修改滚动状态,只需使用rememberScrollState创建一个持久的ScrollState实例。

最终结果应如下所示:

import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll


@Composable
fun HomeScreen(modifier: Modifier = Modifier) {
    Column(
        modifier.verticalScroll(rememberScrollState())
        .padding(vertical = 16.dp)
    ) {

        Spacer(Modifier.height(16.dp))
        SearchBar(Modifier.padding(horizontal = 16.dp))
        HomeSection(title = R.string.align_your_body) {
            AlignYourBodyRow()
        }
        HomeSection(title = R.string.favorite_collections) {
            FavoriteCollectionsGrid()
        }
        Spacer(Modifier.height(16.dp))
    }

}

如需验证可组合项的滚动行为,请限制预览的高度,并在互动式预览中运行它。

@Preview(showBackground = true, backgroundColor = 0xFFF0EAE2, heightDp = 100)
@Composable
fun ScreenContentPreview() {
    MySootheTheme { HomeScreen() }
}

10、底部导航栏 – Material

现在,您已经实现了屏幕内容,可以开始添加窗口装饰了。就MySoothe而言,用户可以通过底部导航栏在不同的屏幕之间切换。

首先,实现此底部导航栏可组合项本身,然后将其添加到应用中。
我们来看一下设计:

image.png

幸运的是,您无需自己从头开始实现整个可组合项。您可以使用Compose Material库中的BottomNavigation可组合项。在BottomNavigation可组合项内,您可以添加一个或多个BottomNavigationItem元素,然后Material库会自动为其设置样式。

先从此底部导航栏的基本所实现着手:

import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavittationItem
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Spa

@Composable
private fun SootheBottomNavigation(modifier: Modifier = Modifier) {
    BottomNavigation(modifier) {
        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.AccoutCircle,
                    contentDescription = null
                )
            },
            label = {
                Text(stringResource(R.string.bottom_navigation_profile))
            },
            selected = false,
            onClick = {}
        )
    }
}

此基本实现如下所示:

image.png

您应该进行一些样式调整。首先,您可以通过设置底部导航栏的backgroundColor形参来更新其北京颜色。为此,您可以使用Material主题中的背景颜色。通过设置背景颜色,图标和文本的颜色会自动适应主题的onBackground颜色。最终解决方案应如下所示:

@Composable

private fun SootheBottomNavigation(modifier: Modifier = Modifier) {
    BottomNavigation(
        backgroundColor = MaterialTheme.colors.background,
        modifier = modifier
    ) {
        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.AccountCirclr,
                    contentDescription = null
                )
            },
            label = {
                Text(stringResource(R.string.bottom_navigation_profile))
            },
            selected = false,
            onClick = {}
        )
    }
}

11、MySoothe应用 – Scaffold

在这最后一步中,创建全屏实现,包含底部导航栏。使用Material的Scaffold可组合项。对于实现Material Design的应用,Scaffold提供了可配置的顶级可组合项。它包含可用于各种Material概念的槽位,其中一个就是底部栏。在此底部栏中,您可以放置在上一步中创建的底部导航栏可组合项。

实现MysootheApp可组合项。这是应用的顶级可组合项,因此您应该:

  • 应用MySootheTheme Material主题
  • 添加Scaffold
  • 将底部栏设置为SootheBottomNavigation可组合项。
  • 将内容设置为HomeScreen可组合项。

最终结果应如下所示:

import androidx.compose.material.Scaffold



@Composable

fun MySootheTheme() {
    MySootheTheme {
        Scaffold(
            bottomBar = { SootheBottomNavigation() }
        ) { padding ->
            HomeScreen(Modifier.padding(padding))
        }
    }
}

您的实现已经完成!如果想要检查您的实现的设计是否能让像素完美呈现,可以下载下面的图片,然后将其与您自己的预览实现进行比较。

image.png

12、恭喜!

翻译原文:Compose 基础知识

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYr8AZq8' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片