Compose Codelab 学习 - Compose 中的基本布局

Compose 中的基本布局

  • 官方文档:https://developer.android.google.cn/codelabs/jetpack-compose-layouts?hl=zh-cn#0
演示
kotlin 复制代码
@Composable
fun SearchBar(
    modifier: Modifier = Modifier
) {
    TextField(
        value = "",
        onValueChange = {},
        modifier = modifier
            .fillMaxWidth()
            .heightIn(min = 56.dp),
        leadingIcon = {
            Icon(
                imageVector = Icons.Default.Search,
                contentDescription = null
            )
        },
        placeholder = {
            Text(stringResource(R.string.placeholder_search))
        },
        colors = TextFieldDefaults.colors(
            unfocusedContainerColor = MaterialTheme.colorScheme.surface,
            focusedContainerColor = MaterialTheme.colorScheme.surface
        ),
    )
}
kotlin 复制代码
@Composable
fun AlignYourBodyElement(
    @DrawableRes drawable: Int,
    @StringRes text: Int,
    modifier: Modifier = Modifier
) {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = modifier
    ) {
        Image(
            painter = painterResource(drawable),
            contentDescription = null,
            modifier = Modifier
                .size(88.dp)
                .clip(CircleShape),
            contentScale = ContentScale.Crop,
        )
        Text(
            text = stringResource(text),
            modifier = Modifier.paddingFromBaseline(top = 24.dp, bottom = 8.dp),
        )
    }
}

class AlignYourBodyData(
    @DrawableRes val drawable: Int,
    @StringRes val text: Int,
)

@Composable
fun AlignYourBodyRow(
    alignYourBodyData: List<AlignYourBodyData>,
    modifier: Modifier = Modifier
) {
    LazyRow(
        horizontalArrangement = Arrangement.spacedBy(8.dp),
        contentPadding = PaddingValues(8.dp),
        modifier = modifier
    ) {
        items(alignYourBodyData) { item ->
            AlignYourBodyElement(item.drawable, item.text)
        }
    }
}
kotlin 复制代码
@Composable
fun FavoriteCollectionCard(
    @DrawableRes drawable: Int,
    @StringRes text: Int,
    modifier: Modifier = Modifier
) {
    Surface(
        shape = MaterialTheme.shapes.medium,
        modifier = modifier
    ) {
        Row(
            verticalAlignment = Alignment.CenterVertically,
            modifier = Modifier.width(255.dp)
        ) {
            Image(
                painter = painterResource(drawable),
                contentDescription = null,
                modifier = Modifier.size(80.dp),
                contentScale = ContentScale.Crop,
            )
            Text(text = stringResource(text), modifier = Modifier.padding(start = 8.dp))
        }
    }
}

class FavoriteCollectionsData(
    @DrawableRes val drawable: Int,
    @StringRes val text: Int,
)

@Composable
fun FavoriteCollectionsGrid(
    favoriteCollectionsData: List<FavoriteCollectionsData>,
    modifier: Modifier = Modifier
) {
    LazyHorizontalGrid(
        rows = GridCells.Fixed(2),
        modifier = modifier.height(208.dp),
        horizontalArrangement = Arrangement.spacedBy(16.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp),
        contentPadding = PaddingValues(16.dp),
    ) {
        items(favoriteCollectionsData) { item ->
            FavoriteCollectionCard(item.drawable, item.text, modifier = Modifier.height(80.dp))
        }
    }
}
kotlin 复制代码
@Composable
fun HomeSection(
    @StringRes title: Int,
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Column(modifier) {
        Text(
            stringResource(title),
            style = MaterialTheme.typography.titleMedium,
            modifier = Modifier
                .paddingFromBaseline(top = 40.dp, bottom = 16.dp)
                .padding(horizontal = 16.dp)
        )
        content()
    }
}

@Composable
fun HomeScreen(modifier: Modifier = Modifier) {
    Column(
        modifier = modifier.verticalScroll(rememberScrollState()),
    ) {
        Spacer(Modifier.height(16.dp))
        SearchBar(Modifier.padding(horizontal = 16.dp))
        HomeSection(title = R.string.align_your_body) {
            AlignYourBodyRow(
                alignYourBodyData = listOf(
                    AlignYourBodyData(
                        drawable = R.drawable.ab1_inversions,
                        text = R.string.ab1_inversions
                    ),
                    AlignYourBodyData(
                        drawable = R.drawable.ab1_inversions,
                        text = R.string.ab1_inversions
                    ),
                    AlignYourBodyData(
                        drawable = R.drawable.ab1_inversions,
                        text = R.string.ab1_inversions
                    ),
                    AlignYourBodyData(
                        drawable = R.drawable.ab1_inversions,
                        text = R.string.ab1_inversions
                    ),
                    AlignYourBodyData(
                        drawable = R.drawable.ab1_inversions,
                        text = R.string.ab1_inversions
                    ),
                ),
            )
        }
        HomeSection(title = R.string.favorite_collections) {
            FavoriteCollectionsGrid(
                favoriteCollectionsData = listOf(
                    FavoriteCollectionsData(
                        drawable = R.drawable.fc2_nature_meditations,
                        text = R.string.fc2_nature_meditations
                    ),
                    FavoriteCollectionsData(
                        drawable = R.drawable.fc2_nature_meditations,
                        text = R.string.fc2_nature_meditations
                    ),
                    FavoriteCollectionsData(
                        drawable = R.drawable.fc2_nature_meditations,
                        text = R.string.fc2_nature_meditations
                    ),
                    FavoriteCollectionsData(
                        drawable = R.drawable.fc2_nature_meditations,
                        text = R.string.fc2_nature_meditations
                    ),
                    FavoriteCollectionsData(
                        drawable = R.drawable.fc2_nature_meditations,
                        text = R.string.fc2_nature_meditations
                    ),
                ),
            )
        }
        Spacer(Modifier.height(16.dp))
    }
}
kotlin 复制代码
@Composable
fun SootheBottomNavigation(modifier: Modifier = Modifier) {
    NavigationBar(
        modifier = modifier
    ) {
        NavigationBarItem(
            icon = {
                Icon(
                    imageVector = Icons.Default.Spa,
                    contentDescription = null
                )
            },
            label = {
                Text(
                    text = stringResource(R.string.bottom_navigation_home)
                )
            },
            selected = true,
            onClick = {}
        )
        NavigationBarItem(
            icon = {
                Icon(
                    imageVector = Icons.Default.AccountCircle,
                    contentDescription = null
                )
            },
            label = {
                Text(
                    text = stringResource(R.string.bottom_navigation_profile)
                )
            },
            selected = false,
            onClick = {}
        )
    }
}

@Composable
fun SootheNavigationRail(modifier: Modifier = Modifier) {
    NavigationRail(
        modifier = modifier.padding(start = 8.dp, end = 8.dp)
    ) {
        Column(
            modifier = modifier.fillMaxHeight(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            NavigationRailItem(
                icon = {
                    Icon(
                        imageVector = Icons.Default.Spa,
                        contentDescription = null
                    )
                },
                label = {
                    Text(
                        text = stringResource(R.string.bottom_navigation_home)
                    )
                },
                selected = true,
                onClick = {}
            )
            Spacer(modifier = Modifier.height(16.dp))
            NavigationRailItem(
                icon = {
                    Icon(
                        imageVector = Icons.Default.AccountCircle,
                        contentDescription = null
                    )
                },
                label = {
                    Text(
                        text = stringResource(R.string.bottom_navigation_profile)
                    )
                },
                selected = false,
                onClick = {}
            )
        }
    }
}
kotlin 复制代码
@Composable
fun MyApp(windowSize: WindowSizeClass) {
    when (windowSize.widthSizeClass) {
        WindowWidthSizeClass.Compact -> {
            Column {
                HomeScreen(Modifier.weight(1f))
                SootheBottomNavigation()
            }
        }

        WindowWidthSizeClass.Expanded -> {
            Row {
                SootheNavigationRail()
                HomeScreen()
            }
        }
    }
}
1、8dp 网格
  1. 8dp 网格是 Android 界面设计中的一套基础对齐系统,它规定所有UI元素的尺寸和间距都应该是 8dp 的整数倍

  2. 所有组件的大小、边距、内边距和位置,都基于 8dp 这个基本单位。例如,常见的按钮高度为 48dp,应用栏高度为 56dp

2、标准的 Compose 组件
kotlin 复制代码
@Composable
fun AlignYourBodyElement(
    modifier: Modifier = Modifier
) {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = modifier
    ) {
        Image(
            painter = painterResource(R.drawable.ab1_inversions),
            contentDescription = null,
            modifier = Modifier
                .size(88.dp)
                .clip(CircleShape),
            contentScale = ContentScale.Crop,
        )
        Text(
            text = stringResource(R.string.ab1_inversions),
            modifier = Modifier.paddingFromBaseline(top = 24.dp, bottom = 8.dp),
        )
    }
}

@Preview(showBackground = true)
@Composable
fun AlignYourBodyElementPreview() {
    AlignYourBodyElement()
}
kotlin 复制代码
@Composable
fun AlignYourBodyElement(
    @DrawableRes drawable: Int,
    @StringRes text: Int,
    modifier: Modifier = Modifier
) {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = modifier
    ) {
        Image(
            painter = painterResource(drawable),
            contentDescription = null,
            modifier = Modifier
                .size(88.dp)
                .clip(CircleShape),
            contentScale = ContentScale.Crop,
        )
        Text(
            text = stringResource(text),
            modifier = Modifier.paddingFromBaseline(top = 24.dp, bottom = 8.dp),
        )
    }
}

@Preview(showBackground = true)
@Composable
fun AlignYourBodyElementPreview() {
    AlignYourBodyElement(
        drawable = R.drawable.ab1_inversions,
        text = R.string.ab1_inversions,
        modifier = Modifier.padding(8.dp)
    )
}
3、painterResource 函数与 stringResource 函数
(1)基本介绍
  • painterResource 和 stringResource 都是 Jetpack Compose 中用来加载资源的可组合函数
  1. painterResource 函数负责加载图片
kotlin 复制代码
@Composable
fun painterResource(@DrawableRes id: Int): Painter {
    val context = LocalContext.current
    val res = resources()
    val value = remember { TypedValue() }
    res.getValue(id, value, true)
    val path = value.string
    // Assume .xml suffix implies loading a VectorDrawable resource
    return if (path?.endsWith(".xml") == true) {
        val imageVector = loadVectorResource(context.theme, res, id, value.changingConfigurations)
        rememberVectorPainter(imageVector)
    } else {
        // Otherwise load the bitmap resource
        val imageBitmap = remember(path, id, context.theme) {
            loadImageBitmapResource(path, res, id)
        }
        BitmapPainter(imageBitmap)
    }
}
  1. stringResource 函数负责加载文字
kotlin 复制代码
@Composable
@ReadOnlyComposable
fun stringResource(@StringRes id: Int): String {
    val resources = resources()
    return resources.getString(id)
}
  • painterResource 函数和 stringResource 函数是对传统 Android 原生 API 的封装,让它们在 Compose 的世界里使用起来更方便、更符合声明式 UI 的风格
(2)演示
kotlin 复制代码
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description)
)
4、手动添加滚动行为
(1)基本介绍
  1. LazyRow 和 LazyHorizontalGrid 等延迟布局会自动添加滚动行为

  2. 在列表中有许多元素或需要加载大型数据集时,需要使用延迟布局,因此一次发出所有项不仅会降低性能,还会拖慢应用的运行速度

  3. 如果列表中的元素数量有限,也可以选择使用简单的 Column 或 Row,然后手动添加滚动行为

  4. 可以使用 verticalScroll 或 horizontalScroll 修饰符。这些修饰符需要 ScrollState,后者包含当前的滚动状态,可用于从外部修改滚动状态

  5. 使用 rememberScrollState 创建一个持久的 ScrollState 实例

kotlin 复制代码
fun Modifier.verticalScroll(
    state: ScrollState,
    enabled: Boolean = true,
    flingBehavior: FlingBehavior? = null,
    reverseScrolling: Boolean = false
) = scroll(
    state = state,
    isScrollable = enabled,
    reverseScrolling = reverseScrolling,
    flingBehavior = flingBehavior,
    isVertical = true
)
复制代码
fun Modifier.horizontalScroll(
    state: ScrollState,
    enabled: Boolean = true,
    flingBehavior: FlingBehavior? = null,
    reverseScrolling: Boolean = false
) = scroll(
    state = state,
    isScrollable = enabled,
    reverseScrolling = reverseScrolling,
    flingBehavior = flingBehavior,
    isVertical = false
)
(2)演示
kotlin 复制代码
Column(
    modifier = Modifier.verticalScroll(rememberScrollState()),
) {
    ...
}
5、导航栏
kotlin 复制代码
@Composable
fun SootheBottomNavigation(modifier: Modifier = Modifier) {
    NavigationBar(
        modifier = modifier
    ) {
        NavigationBarItem(
            icon = {
                Icon(
                    imageVector = Icons.Default.Spa,
                    contentDescription = null
                )
            },
            label = {
                Text(
                    text = stringResource(R.string.bottom_navigation_home)
                )
            },
            selected = true,
            onClick = {}
        )
        NavigationBarItem(
            icon = {
                Icon(
                    imageVector = Icons.Default.AccountCircle,
                    contentDescription = null
                )
            },
            label = {
                Text(
                    text = stringResource(R.string.bottom_navigation_profile)
                )
            },
            selected = false,
            onClick = {}
        )
    }
}
  • 适配横屏模式下的显示效果
kotlin 复制代码
@Composable
fun SootheNavigationRail(modifier: Modifier = Modifier) {
    NavigationRail(
        modifier = modifier.padding(start = 8.dp, end = 8.dp)
    ) {
        Column(
            modifier = modifier.fillMaxHeight(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            NavigationRailItem(
                icon = {
                    Icon(
                        imageVector = Icons.Default.Spa,
                        contentDescription = null
                    )
                },
                label = {
                    Text(
                        text = stringResource(R.string.bottom_navigation_home)
                    )
                },
                selected = true,
                onClick = {}
            )
            Spacer(modifier = Modifier.height(16.dp))
            NavigationRailItem(
                icon = {
                    Icon(
                        imageVector = Icons.Default.AccountCircle,
                        contentDescription = null
                    )
                },
                label = {
                    Text(
                        text = stringResource(R.string.bottom_navigation_profile)
                    )
                },
                selected = false,
                onClick = {}
            )
        }
    }
}
相关推荐
ii_best1 小时前
手机自动化脚本按键精灵实战:随机布局安全数字键盘的自动化输入方案
android·运维·ios·自动化·手机
2601_965798471 小时前
Boutique Business Consulting WordPress Architecture & SEO Setup
android·theme·wordpress
莫得感情 o1 小时前
并发 11 · 同步工具类
java·并发
三少爷的鞋2 小时前
Android 架构进阶:为什么项目越大,越需要把对象创建权拿走
android
杜子麟4 小时前
Android studio模拟器离线安装
android·macos·android studio
年小个大6 小时前
受 go-zero 启发,我给 Flutter 整了套 MVI-BLoC 脚手架
android·flutter·架构
chuan.bai7 小时前
Java RAG 实战(第 11 篇):RAG 知识工作台网页
java·开发语言·人工智能
0x5310 小时前
网站通信(一)
java
Terra.K10 小时前
Java异常学习[特殊字符]
java·开发语言·学习