<h1 align="center">灵活底部表单</h1></br>
<p align="center">
<a href="https://opensource.org/licenses/Apache-2.0"><img alt="许可证" src="https://yellow-cdn.veclightyear.com/87312a0a/e28b0396-452d-4e50-8113-4452aaa3eaec.svg"/></a>
<a href="https://android-arsenal.com/api?level=21"><img alt="API" src="https://yellow-cdn.veclightyear.com/87312a0a/e1292ee3-bacc-4d7a-b31d-96940822848a.svg?style=flat"/></a>
<a href="https://github.com/skydoves/FlexibleBottomSheet/actions/workflows/android.yml"><img alt="构建状态"
src="https://github.com/skydoves/FlexibleBottomSheet/actions/workflows/android.yml/badge.svg"/></a>
<a href="https://androidweekly.net/issues/issue-599"><img alt="Android周刊" src="https://yellow-cdn.veclightyear.com/87312a0a/661cb9d2-76a5-4008-aeda-d7436ad919aa.svg"/></a>
<a href="https://github.com/skydoves"><img alt="个人资料" src="https://yellow-cdn.veclightyear.com/87312a0a/9b67f457-4a13-493c-a05c-8fbd0344f331.svg"/></a>
</p><br>
<p align="center">
🐬 FlexibleBottomSheet 是一个先进的 Compose 多平台底部表单,支持分段大小调整、非模态类型,并允许像 Google 地图一样在底部表单后面进行交互。它还提供额外的便利功能,包括指定表单大小、监控表单状态以及更多自定义选项。
</p><br>
<p align="center">
<img src="https://yellow-cdn.veclightyear.com/87312a0a/e57cf1e6-843d-49b6-a666-31f58f5ad3fc.png" width="270"/>
<img src="https://yellow-cdn.veclightyear.com/87312a0a/45e75b96-7a18-4d47-8072-77a5db8c90d1.png" width="270"/>
<img src="https://yellow-cdn.veclightyear.com/87312a0a/e89ae00a-3584-4555-b8c1-b264a4bc9e98.png" width="270"/>
</p>
## 下载
[](https://search.maven.org/search?q=g:%22com.github.skydoves%22%20AND%20a:%22flexible-core%22)
### Gradle
将以下依赖添加到你的**模块**的 `build.gradle` 文件中:
```gradle
dependencies {
// compose material
implementation("com.github.skydoves:flexible-bottomsheet-material:0.1.4")
// compose material3
implementation("com.github.skydoves:flexible-bottomsheet-material3:0.1.4")
}
对于 Kotlin 多平台,将以下依赖添加到你的**模块**的 `build.gradle.kts` 文件中:
```gradle
sourceSets {
val commonMain by getting {
dependencies {
// compose material
implementation("com.github.skydoves:flexible-bottomsheet-material:$version")
// compose material3
implementation("com.github.skydoves:flexible-bottomsheet-material3:$version")
}
}
}
使用方法
你可以使用 FlexibleBottomSheet
实现灵活的底部表单,类似于 Compose Material 3 提供的 ModalBottomSheet
。本质上,如果不改变任何属性,你可以实现与 ModalBottomSheet
相同的行为。
FlexibleBottomSheet
<img src="https://yellow-cdn.veclightyear.com/87312a0a/8f62cf38-c1f9-4d92-8ef2-f20e8c92ad55.gif" width="280px" align="right">
这是 `FlexibleBottomSheet` 的基本示例,它是模态的,允许为每个展开状态自定义表单大小,并提供三种不同的展开状态(完全展开、中等展开、略微展开):
```kotlin
FlexibleBottomSheet(
onDismissRequest = onDismissRequest,
sheetState = rememberFlexibleBottomSheetState(
flexibleSheetSize = FlexibleSheetSize(
fullyExpanded = 0.9f,
intermediatelyExpanded = 0.5f,
slightlyExpanded = 0.15f,
),
isModal = true,
skipSlightlyExpanded = false,
),
containerColor = Color.Black,
) {
Text(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
text = "这是灵活底部表单",
textAlign = TextAlign.Center,
color = Color.White,
)
}
```
### FlexibleBottomSheetState
`FlexibleBottomSheetState` 是一个重要概念,必须绑定到 `FlexibleBottomSheet` 以管理其状态变化。它还允许你自定义底部表单的 UI/UX 行为,并手动控制展开/隐藏底部表单。你可以使用 `rememberFlexibleBottomSheetState` 来记住 `FlexibleBottomSheetState`,如下例所示:
```kotlin
FlexibleBottomSheet(
onDismissRequest = onDismissRequest,
sheetState = rememberFlexibleBottomSheetState(
skipSlightlyExpanded = false,
skipIntermediatelyExpanded = false,
isModal = true,
containSystemBars = false,
allowNestedScroll = true,
flexibleSheetSize = FlexibleSheetSize(
fullyExpanded = 1.0f,
intermediatelyExpanded = 0.5f,
slightlyExpanded = 0.25f
)
),
) {
..
}
```
你可以通过使用 `FlexibleBottomSheetState` 手动展开或隐藏底部表单,如下面的代码所示:
<img src="https://yellow-cdn.veclightyear.com/87312a0a/6e2bf373-0f47-4d33-bd3a-6705dc7af027.gif" width="300px" align="right">
```kotlin
val scope = rememberCoroutineScope()
val sheetState = rememberFlexibleBottomSheetState(
flexibleSheetSize = FlexibleSheetSize(fullyExpanded = 0.9f),
isModal = true,
skipSlightlyExpanded = false,
)
FlexibleBottomSheet(
sheetState = sheetState,
containerColor = Color.Black,
onDismissRequest = onDismissRequest
) {
Button(
modifier = Modifier.align(Alignment.CenterHorizontally),
onClick = {
scope.launch {
when (sheetState.swipeableState.currentValue) {
FlexibleSheetValue.SlightlyExpanded -> sheetState.intermediatelyExpand()
FlexibleSheetValue.IntermediatelyExpanded -> sheetState.fullyExpand()
else -> sheetState.hide()
}
}
},
) {
Text(text = "展开或隐藏")
}
}
### 底部表单展开状态
灵活底部表单提供了四种主要的表单状态,称为 `FlexibleValues`:
- **完全展开**: 表单以完全展开的高度可见。这是必需的,不能跳过。
- **中等展开**: 表单以中等展开的高度可见。可以通过将 `skipIntermediatelyExpanded` 设置为 `true` 来跳过。
- **略微展开**: 表单以略微展开的高度可见。默认情况下被跳过,但可以通过将 `skipSlightlyExpanded` 设置为 `false` 来启用。
- **隐藏**: 表单在屏幕上完全不可见。如果你永远不想关闭并保持显示底部表单,可以将 `skipHiddenState` 设置为 `true`。
你可以选择跳过**中等展开**和**略微展开**状态,如下所示:
```kotlin
FlexibleBottomSheet(
onDismissRequest = onDismissRequest,
sheetState = rememberFlexibleBottomSheetState(
skipSlightlyExpanded = false,
skipIntermediatelyExpanded = false
),
) {
..
}
展开尺寸
FlexibleBottomSheet 允许你根据其状态自定义底部表单的展开尺寸和内容大小。这些约束通过将比率乘以最大显示高度(不包括系统栏,即状态栏和导航栏)来计算。你可以通过将 FlexibleSheetSize
设置到 rememberFlexibleBottomSheetState
中来轻松自定义展开的表单大小,如下面的代码所示:
FlexibleBottomSheet(
onDismissRequest = onDismissRequest,
sheetState = rememberFlexibleBottomSheetState(
flexibleSheetSize = FlexibleSheetSize(
fullyExpanded = 0.85f,
intermediatelyExpanded = 0.45f,
slightlyExpanded = 0.15f,
),
)
) {
..
}
完全展开 (0.85) | 中等展开 (0.45) | 略微展开 (0.15) |
---|
<img src="https://yellow-cdn.veclightyear.com/87312a0a/8a8089bb-bd4d-419b-9b41-07730bf01c81.png" align="center" width="320px" height ="480px"/> | <img src="https://yellow-cdn.veclightyear.com/87312a0a/a13b6639-2445-4350-9a52-54653b782eac.png" align="center" width="320px" height ="480px"/> | <img src="https://yellow-cdn.veclightyear.com/87312a0a/a7d7a4b6-37f0-4072-9e7f-d6f0ee7a5479.png" align="center" width="320px" height ="480px"/> |
非模态底部表单
<p align="center">
<img src="https://yellow-cdn.veclightyear.com/87312a0a/e57cf1e6-843d-49b6-a666-31f58f5ad3fc.png" width="270"/>
<img src="https://yellow-cdn.veclightyear.com/87312a0a/45e75b96-7a18-4d47-8072-77a5db8c90d1.png" width="270"/>
<img src="https://yellow-cdn.veclightyear.com/87312a0a/e89ae00a-3584-4555-b8c1-b264a4bc9e98.png" width="270"/>
</p>
如果你需要在底部表单显示在屏幕上时与表单外部进行交互(类似于 Google 地图的样式),你可以通过将 `FlexibleBottomSheet` 可组合项的 `isModal` 属性设置为 **false** 来轻松实现,如下所示:
```kotlin
FlexibleBottomSheet(
onDismissRequest = onDismissRequest,
sheetState = rememberFlexibleBottomSheetState(
isModal = false,
skipSlightlyExpanded = false,
),
) {
..
}
```
你将看到以下结果:
<img src="https://yellow-cdn.veclightyear.com/87312a0a/98a018bc-5245-4e78-b634-86770d57116b.gif" width="320px">
### 通过监控值变化动态生成内容
你可以通过跟踪底部表单状态变化来动态组合底部表单内容。下面的示例代码演示了如何轻松观察表单状态并相应地调整文本大小:
<img src="https://yellow-cdn.veclightyear.com/87312a0a/41446b6d-bfdd-4c79-b1e5-e330b9cc520d.gif" width="290px" align="right">
```kotlin
var currentSheetTarget by remember {
mutableStateOf(FlexibleSheetValue.IntermediatelyExpanded)
}
FlexibleBottomSheet(
onDismissRequest = onDismissRequest,
sheetState = rememberFlexibleBottomSheetState(
skipSlightlyExpanded = false
),
onTargetChanges = { sheetValue ->
currentSheetTarget = sheetValue
},
containerColor = Color.Black,
) {
Text(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
text = "这是灵活底部表单",
textAlign = TextAlign.Center,
color = Color.White,
fontSize = when (currentSheetTarget) {
FlexibleSheetValue.FullyExpanded -> 28.sp
FlexibleSheetValue.IntermediatelyExpanded -> 20.sp
else -> 12.sp
},
)
}
你还可以使用 Compose 动画库 [Orbital](https://github.com/skydoves/Orbital) 实现动态内容。
<img src="https://yellow-cdn.veclightyear.com/87312a0a/036b9909-8b3d-4d95-866f-d7e2ea919650.gif" width="320px" align="cemter">
### 嵌套滚动
`FlexibleBottomSheet` 本身支持嵌套滚动,允许与 `LazyColumn`、`LazyRow` 等组件无缝集成。但是,如果你希望禁用嵌套滚动,可以通过在 `rememberFlexibleBottomSheetState` 中将 `allowNestedScroll` 设置为 `false` 来实现。
```kotlin
FlexibleBottomSheet(
onDismissRequest = onDismissRequest,
sheetState = rememberFlexibleBottomSheetState(
allowNestedScroll = false
),
) {
..
}
你将看到以下区别:
启用
许可证
由 2023 skydoves (Jaewoong Eum) 设计和开发
根据 Apache 许可证 2.0 版("许可证")授权;
除非遵守许可证,否则您不得使用此文件。
您可以在以下网址获取许可证副本:
http://www.apache.org/licenses/LICENSE-2.0
除非适用法律要求或书面同意,否则根据许可证分发的软件是基于"按原样"分发的,
不附带任何明示或暗示的担保或条件。
有关许可证下的特定语言管理权限和限制,请参阅许可证。