Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/succlz123/compose-screen
A simple, highly customizable compose navigation component for Android & Desktop platform.
https://github.com/succlz123/compose-screen
android compose-android compose-desktop compose-navigation compose-ui composer composer-library jetpack-compose kotlin
Last synced: about 2 hours ago
JSON representation
A simple, highly customizable compose navigation component for Android & Desktop platform.
- Host: GitHub
- URL: https://github.com/succlz123/compose-screen
- Owner: succlz123
- Created: 2022-09-15T22:34:33.000Z (about 2 years ago)
- Default Branch: master
- Last Pushed: 2022-10-06T14:06:41.000Z (about 2 years ago)
- Last Synced: 2024-04-16T11:24:57.268Z (7 months ago)
- Topics: android, compose-android, compose-desktop, compose-navigation, compose-ui, composer, composer-library, jetpack-compose, kotlin
- Language: Kotlin
- Homepage:
- Size: 505 KB
- Stars: 28
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
![banner][file:banner]
[file:banner]: screenshot/Banner.png
# 介绍
一个简单并提供高度扩展功能的 Compose 导航组件,同时支持 Android 和 Desktop 平台。
# 常用功能
# 使用
## 下载
```
// Android
implementation("io.github.succlz123:compose-screen-android:0.0.2")
// Desktop
implementation("io.github.succlz123:compose-screen-desktop:0.0.2")
```## 开始
### Android
```kotlin
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// 生命周期,按键返回等都由 activity 接管
ScreenContainer(this) {
// Screen Host
}
// 或者分别设置相应所有者
ScreenContainer(this, this, this, this) {
// Screen Host
}
}
}
}
```### Desktop
```kotlin
fun main() = application {
val size = DpSize(480.dp, 720.dp)
val windowState = rememberWindowState(size = size)
ScreenContainer(
title = "Compose Screen",
state = windowState,
onCloseRequest = {
exitApplication()
},
) {
// Screen Host
}
}
```### 通用
#### Screen Host
```kotlin
// 创建 screen navigator
val screenNavigator = rememberScreenNavigator()// 初始化应用页面,确定根页面
ScreenHost(screenNavigator = screenNavigator, rootScreenName = "your root screen") {
// 注册添加你所需要展示的页面
groupScreen(screenName = ("your root screen")) {
XXXScreen()
}
groupScreen(screenName = "your YYY screen") {
YYYScreen()
}
itemScreen(screenName = "your popup screen") {
ZZZPopupScreen()
}
...
}
```#### 导航
```kotlin
// 获取 screenNavigator
val screenNavigator = LocalScreenNavigator.current// 普通导航
screenNavigator.push(screenName = "your screen")// 导航携带参数
val count = 1
screenNavigator.push(
screenName = "your screen",
arguments = ScreenArgs.putValue("KEY_COUNT", count)
)// singleTop 栈顶复用
screenNavigator.push(
screenName = "your screen",
pushOptions = PushOptions().apply {
removePredicate = PushOptions.SingleTopPredicate("your screen")
}
)// singleTask 栈内复用
screenNavigator.push(
screenName = "your screen",
pushOptions = PushOptions().apply {
removePredicate = PushOptions.SingleTaskPredicate("your screen")
}
)// 导航同时移除当前页面
screenNavigator.push(
screenName = "your screen",
pushOptions = PushOptions().apply {
removePredicate = PushOptions.PopItselfPredicate()
}
)// 移除任意页面
screenNavigator.remove(screenName = "your screen")
```#### 返回
```kotlin
screenNavigator.pop()
```##### 返回到某一页面
```kotlin
screenNavigator.popTo(screenName = "ZZZScreen")
```##### 返回并获得结果
```kotlin
val onResult = LocalScreenRecord.current.result
```##### 返回拦截
```kotlin
screenNavigator.pop(popOptions = PopOptions(popStackFinalInterceptor = { backstackList, _, _ ->
backstackList.size > 10
}))
```#### 浮窗
##### 弹窗
PopupScreen 层级高于 Screen,附属于当前绑定的 Group Screen。退出 Group Screen 时,PopupScreen 同时消失。
```kotlin
ScreenHost(screenNavigator = screenNavigator, rootScreenName = Manifest.MainScreen) {
// register your popup screen
popup(screenName = Manifest.DialogPopupScreen) {
DialogPopupScreen(screenNavigator)
}
}// show th dialog
screenNavigator.push(Manifest.DialogPopupScreen)
```##### 吐司
全局只有一个吐司,吐司永远在所有页面层级之上,切换页面不会导致吐司消失。
```kotlin
// 默认的吐司
screenNavigator.toast("Your toast.")// 更多配置的默认的吐司
screenNavigator.toast(
arguments = ScreenArgs.putValue(KEY_TOAST_TIME, ARGS_TOAST_TIME_SHORT)
.putValue(KEY_TOAST_TIME_LOCATION, ARGS_TOAST_TIME_LOCATION_BOTTOM_CENTER)
.putValue(KEY_TOAST_MSG, "Your toast."))// 显示自定义的吐司
screenNavigator.toast {
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
...
}
}
```##### 浮动窗口
同一个 Group Screen 中只能存在一个 PopupWindow。退出 Screen PopupWindow 同时消失。
```kotlin
Column(modifier = Modifier.fillMaxSize().background(Color.White)) {
...
PopupWindowLayout(displayContent = {
// the content which you want to display
...
}, clickableContent = {
// such as a button layout
...
})
...
}
```#### 生命周期
针对 Compose 为了更好的处理在某些特殊场景下的需要,ScreenLifecycleCallback 提供了 screenLifecycleState 和 hostLifecycleState 生命周期回调。
##### hostLifecycleState
宿主 Android/Desktop 生命周期回调
> Android 下目前 Compose 收不到 onCreate onDestroy 相应回调
| Compose Screen - Host Lifecyle | Android | Desktop |
|--------------------------------|-----------|------------------------|
| | onCreate | |
| | onStart | |
| RESUMED | onResume | active |
| PAUSED | onPasuse | inActive - isMinimized |
| | onStop | |
| | onDestroy | |
| onDestroy | | onCloseRequest |##### screenLifecycleState
Screen 抽象后的生命周期,通常来讲业务逻辑不应该依赖与此,切换页面会导致在此触发的 OnCreate 和 OnResume。
| Compose Screen - Screen Lifecycle | Screen |
|-----------------------------------|-------------------------------------------|
| CREATED | Push the new screen record into the stack |
| | |
| RESUMED | Check the host lifecycle - onResume |
| PAUSED | Check the host lifecycle - onPause |
| | |
| PAUSED | A new screen was dispalyed |
| DESTROYED | The screen record was out of the stack |```kotlin
ScreenLifecycleCallback(screenRecord, screenLifecycleState = {
println("Screen lifecycle - $countValue: ${it.name}")
if (it == ComposeLifecycle.State.DESTROYED) {
screenNavigator.toast("Screen lifecycle - $countValue: is destroyed")
}
}, hostLifecycleState = {
println(">>> Host lifecycle: ${getPlatformName()} - ${it.name} <<<")
})
```#### 视图模块
针对不同场景下的 ViewModel 使用, Compose Screen 提供了 viewModel,sharedViewModel,globalViewModel,androidViewModel 的扩展方法来方便使用。
##### Compose ViewModel
- viewModel
```kotlin
// 绑定到当前 group screen 的 ViewModel,当 group screen 出栈的时候,该 ViewModel 被销毁
val viewModel = viewModel { YourViewModel() }
```- sharedViewModel
```kotlin
// XXX -> YYY,当 YYY 出栈的时候,sharedViewModel 将继续存在,当 XXX 也出栈的时候, sharedViewModel 才被销毁
@Composable
fun XXXScreen(){
val sharedViewModel = sharedViewModel { YourViewModel() }
}@Composable
fun YYYScreen(){
val sharedViewModel = sharedViewModel { YourViewModel() }
}
```- globalViewModel
```kotlin
// 被绑定到 Screen Mananger 上的 ViewModel,全局唯一,只有 Screen Mananger 不在后才被销毁
val globalViewModel = globalViewModel { YourViewModel() }
```##### Android ViewModel
```kotlin
// Android 平台独有,通过初始化时传入的 ViewModelStoreOwner,来获取或者生成 AndroidX 的 ViewModel.
val androidViewModel = androidViewModel { YourAndroidViewModel() }
```#### 动画
##### 转场动画
框架内已经封装了几个常见转场动画,如下是右边进左边出的转场动画
```kotlin
screenNavigator.push(
"your screen",
pushOptions = PushOptions(
pushTransition = ScreenTransitionRightInLeftOutPush(),
popTransition = ScreenTransitionRightInLeftOutPop()
)
)
```#### 响应系统返回
##### Android
在 Compose Screen 初始化时,传入 OnBackPressedDispatcherOwner, 就可以响应系统返回按键。
##### Desktop
可以通过 enableEscBack 来开启关闭 Compose Screen 响应 ESC 按键返回
#### 横竖屏 UI 适配
```kotlin
val windowSizeOwner = LocalScreenWindowSizeOwner.current
val windowWidth = remember {
windowSizeOwner.getWindowHolder().size.value.width.toInt()
}
val windowHeight = remember {
windowSizeOwner.getWindowHolder().size.value.height.toInt()
}
val windowSizeClass = remember {
windowSizeOwner.getWindowHolder().sizeClass.value
}
// 具体参考 https://developer.android.com/jetpack/compose/layouts/adaptive
when (windowSizeClass) {
ScreenWindowSizeClass.Compact -> {}
ScreenWindowSizeClass.Medium -> {}
ScreenWindowSizeClass.Expanded -> {}
}
```#### Android 异常状态恢复
目前已自动处理了 Android 横竖屏切换或者配置变化下导致的异常状态恢复
# 感谢
- https://developer.android.com/jetpack/compose/navigation
- https://github.com/bytedance/scene
- https://github.com/olshevski/compose-navigation-reimagined