{"id":18644331,"url":"https://github.com/succlz123/compose-screen","last_synced_at":"2025-10-04T01:48:38.123Z","repository":{"id":59619116,"uuid":"537227166","full_name":"succlz123/compose-screen","owner":"succlz123","description":"A simple, highly customizable compose navigation component for Android \u0026 Desktop platform.","archived":false,"fork":false,"pushed_at":"2025-08-30T13:30:32.000Z","size":538,"stargazers_count":29,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-12T04:55:43.832Z","etag":null,"topics":["android","compose-android","compose-desktop","compose-navigation","compose-ui","composer","composer-library","jetpack-compose","kotlin"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/succlz123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-09-15T22:34:33.000Z","updated_at":"2025-06-19T03:34:22.000Z","dependencies_parsed_at":"2025-09-12T04:41:48.778Z","dependency_job_id":"58e3ed9c-78f9-4c2a-8d99-bb2006c5ee3f","html_url":"https://github.com/succlz123/compose-screen","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/succlz123/compose-screen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/succlz123%2Fcompose-screen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/succlz123%2Fcompose-screen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/succlz123%2Fcompose-screen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/succlz123%2Fcompose-screen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/succlz123","download_url":"https://codeload.github.com/succlz123/compose-screen/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/succlz123%2Fcompose-screen/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278254465,"owners_count":25956598,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-03T02:00:06.070Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","compose-android","compose-desktop","compose-navigation","compose-ui","composer","composer-library","jetpack-compose","kotlin"],"created_at":"2024-11-07T06:11:32.330Z","updated_at":"2025-10-04T01:48:38.106Z","avatar_url":"https://github.com/succlz123.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"![banner][file:banner]\n\n[file:banner]: screenshot/Banner.png\n\n\u003cimg src=\"https://img.shields.io/static/v1?label=compose-screen\u0026message=0.0.2\u0026color=success\"/\u003e\n\n\u003cimg src=\"https://img.shields.io/static/v1?label=platform\u0026message=Android\u0026color=green\"/\u003e   \u003cimg src=\"https://img.shields.io/static/v1?label=platform\u0026message=Desktop\u0026color=blue\"/\u003e\n\n# 介绍\n\n一个简单并提供高度扩展功能的 Compose 导航组件，同时支持 Android 和 Desktop 平台。\n\n# 常用功能\n\n\u003cimg src=\"https://github.com/succlz123/compose-screen/blob/master/screenshot/Navigation.png?raw=true\" width=\"460\" height=\"725\"/\u003e\u003cbr/\u003e\n\n# 使用\n\n## 下载\n\n```\n// Android\nimplementation(\"io.github.succlz123:compose-screen-android:0.0.2\")\n// Desktop\nimplementation(\"io.github.succlz123:compose-screen-desktop:0.0.2\")\n```\n\n## 开始\n\n### Android\n```kotlin\nclass MainActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContent {\n            // 生命周期，按键返回等都由 activity 接管\n            ScreenContainer(this) {\n                // Screen Host\n            }\n            // 或者分别设置相应所有者\n            ScreenContainer(this, this, this, this) {\n                // Screen Host\n            }\n        }\n    }\n}\n```\n\n### Desktop\n\n```kotlin\nfun main() = application {\n    val size = DpSize(480.dp, 720.dp)\n    val windowState = rememberWindowState(size = size)\n    ScreenContainer(\n        title = \"Compose Screen\",\n        state = windowState,\n        onCloseRequest = {\n            exitApplication()\n        },\n    ) {\n        // Screen Host\n    }\n}\n```\n\n### 通用 \n\n#### Screen Host\n\n```kotlin\n// 创建 screen navigator\nval screenNavigator = rememberScreenNavigator()\n\n// 初始化应用页面，确定根页面\nScreenHost(screenNavigator = screenNavigator, rootScreenName = \"your root screen\") {\n    \n    // 注册添加你所需要展示的页面\n    groupScreen(screenName = (\"your root screen\")) {\n        XXXScreen()\n    }\n    groupScreen(screenName = \"your YYY screen\") {\n        YYYScreen()\n    }\n    itemScreen(screenName = \"your popup screen\") {\n        ZZZPopupScreen()\n    }\n    ...\n    \n }\n```\n\n#### 导航\n\n```kotlin\n// 获取 screenNavigator\nval screenNavigator = LocalScreenNavigator.current\n\n// 普通导航\nscreenNavigator.push(screenName = \"your screen\")\n\n// 导航携带参数\nval count = 1\nscreenNavigator.push(\n    screenName = \"your screen\",\n    arguments = ScreenArgs.putValue(\"KEY_COUNT\", count)\n)\n\n// singleTop 栈顶复用\nscreenNavigator.push(\n    screenName = \"your screen\",\n    pushOptions = PushOptions().apply {\n            removePredicate = PushOptions.SingleTopPredicate(\"your screen\")\n        }\n)\n\n// singleTask 栈内复用\nscreenNavigator.push(\n    screenName = \"your screen\",\n    pushOptions = PushOptions().apply {\n            removePredicate = PushOptions.SingleTaskPredicate(\"your screen\")\n        }\n)\n\n// 导航同时移除当前页面\nscreenNavigator.push(\n    screenName = \"your screen\",\n    pushOptions = PushOptions().apply {\n            removePredicate = PushOptions.PopItselfPredicate()\n        }\n)\n\n// 移除任意页面\nscreenNavigator.remove(screenName = \"your screen\")\n```\n\n#### 返回\n\n```kotlin\nscreenNavigator.pop()\n```\n\n##### 返回到某一页面\n\n```kotlin\nscreenNavigator.popTo(screenName = \"ZZZScreen\")\n```\n\n##### 返回并获得结果\n\n```kotlin\nval onResult = LocalScreenRecord.current.result\n```\n\n##### 返回拦截\n\n```kotlin\nscreenNavigator.pop(popOptions = PopOptions(popStackFinalInterceptor = { backstackList, _, _ -\u003e\n    backstackList.size \u003e 10\n}))\n```\n\n#### 浮窗\n\n##### 弹窗\n\n\u003cimg src=\"https://github.com/succlz123/compose-screen/blob/master/screenshot/Dialog.png?raw=true\" width=\"517\" height=\"583\"/\u003e\u003cbr/\u003e\n\nPopupScreen 层级高于 Screen，附属于当前绑定的 Group Screen。退出 Group Screen 时，PopupScreen 同时消失。\n\n```kotlin\nScreenHost(screenNavigator = screenNavigator, rootScreenName = Manifest.MainScreen) {\n    // register your popup screen\n    popup(screenName = Manifest.DialogPopupScreen) {\n            DialogPopupScreen(screenNavigator)\n        }\n    }\n\n// show th dialog\nscreenNavigator.push(Manifest.DialogPopupScreen)\n```\n\n##### 吐司\n\n\u003cimg src=\"https://github.com/succlz123/compose-screen/blob/master/screenshot/Toast.png?raw=true\" width=\"517\" height=\"583\"/\u003e\u003cbr/\u003e\n\n\n全局只有一个吐司，吐司永远在所有页面层级之上，切换页面不会导致吐司消失。\n\n```kotlin\n// 默认的吐司\nscreenNavigator.toast(\"Your toast.\")\n\n// 更多配置的默认的吐司\nscreenNavigator.toast(\n    arguments = ScreenArgs.putValue(KEY_TOAST_TIME, ARGS_TOAST_TIME_SHORT)\n            .putValue(KEY_TOAST_TIME_LOCATION, ARGS_TOAST_TIME_LOCATION_BOTTOM_CENTER)\n            .putValue(KEY_TOAST_MSG, \"Your toast.\"))\n\n// 显示自定义的吐司\nscreenNavigator.toast {\n    BoxWithConstraints(modifier = Modifier.fillMaxSize()) {\n        ...\n    }\n}\n```\n\n##### 浮动窗口\n\n\u003cimg src=\"https://github.com/succlz123/compose-screen/blob/master/screenshot/PopupWindow.png?raw=true\" width=\"517\" height=\"583\"/\u003e\u003cbr/\u003e\n\n同一个 Group Screen 中只能存在一个 PopupWindow。退出 Screen PopupWindow 同时消失。\n\n```kotlin\nColumn(modifier = Modifier.fillMaxSize().background(Color.White)) {\n        ...\n        PopupWindowLayout(displayContent = {\n                        // the content which you want to display\n                        ...\n                    }, clickableContent = {\n                        // such as a button layout\n                        ...\n                    })\n        ...\n}\n```\n\n#### 生命周期\n\n针对 Compose 为了更好的处理在某些特殊场景下的需要，ScreenLifecycleCallback 提供了 screenLifecycleState 和 hostLifecycleState 生命周期回调。\n\n##### hostLifecycleState\n\n宿主 Android/Desktop 生命周期回调\n\n\u003e Android 下目前 Compose 收不到 onCreate onDestroy 相应回调\n\n| Compose Screen - Host Lifecyle | Android   | Desktop                |\n|--------------------------------|-----------|------------------------|\n|                                | onCreate  |                        |\n|                                | onStart   |                        |\n| RESUMED                        | onResume  | active                 |\n| PAUSED                         | onPasuse  | inActive - isMinimized |\n|                                | onStop    |                        |\n|                                | onDestroy |                        |\n| onDestroy                      |           | onCloseRequest         |\n\n##### screenLifecycleState\n\nScreen 抽象后的生命周期，通常来讲业务逻辑不应该依赖与此，切换页面会导致在此触发的 OnCreate 和 OnResume。\n\n| Compose Screen - Screen Lifecycle | Screen                                    |\n|-----------------------------------|-------------------------------------------|\n| CREATED                          | Push the new screen record into the stack | \n|                                   |                                           | \n| RESUMED                          | Check the host lifecycle - onResume       |  \n| PAUSED                           | Check the host lifecycle - onPause        |  \n|                                   |                                           |  \n| PAUSED                         | A new screen was dispalyed                | \n| DESTROYED                         | The screen record was out of the stack              | \n\n```kotlin\nScreenLifecycleCallback(screenRecord, screenLifecycleState = {\n    println(\"Screen lifecycle - $countValue: ${it.name}\")\n    if (it == ComposeLifecycle.State.DESTROYED) {\n        screenNavigator.toast(\"Screen lifecycle - $countValue: is destroyed\")\n    }\n}, hostLifecycleState = {\n    println(\"\u003e\u003e\u003e Host lifecycle: ${getPlatformName()} - ${it.name} \u003c\u003c\u003c\")\n})\n```\n\n#### 视图模块\n\n针对不同场景下的 ViewModel 使用, Compose Screen 提供了 viewModel，sharedViewModel，globalViewModel，androidViewModel 的扩展方法来方便使用。\n\n##### Compose ViewModel\n\n- viewModel\n\n```kotlin\n// 绑定到当前 group screen 的 ViewModel，当 group screen 出栈的时候，该 ViewModel 被销毁\nval viewModel = viewModel { YourViewModel() }\n```\n\n- sharedViewModel\n\n```kotlin\n// XXX -\u003e YYY，当 YYY 出栈的时候，sharedViewModel 将继续存在，当 XXX 也出栈的时候， sharedViewModel 才被销毁\n@Composable\nfun XXXScreen(){\n    val sharedViewModel = sharedViewModel { YourViewModel() }\n}\n\n@Composable\nfun YYYScreen(){\n    val sharedViewModel = sharedViewModel { YourViewModel() }\n}\n```\n\n- globalViewModel\n\n```kotlin\n// 被绑定到 Screen Mananger 上的 ViewModel，全局唯一，只有 Screen Mananger 不在后才被销毁\nval globalViewModel = globalViewModel { YourViewModel() }\n```\n\n##### Android ViewModel\n\n```kotlin\n// Android 平台独有，通过初始化时传入的 ViewModelStoreOwner，来获取或者生成 AndroidX 的 ViewModel.\nval androidViewModel = androidViewModel { YourAndroidViewModel() }\n```\n\n#### 动画\n\n##### 转场动画\n\n框架内已经封装了几个常见转场动画，如下是右边进左边出的转场动画\n\n```kotlin\nscreenNavigator.push(\n    \"your screen\",\n    pushOptions = PushOptions(\n        pushTransition = ScreenTransitionRightInLeftOutPush(),\n        popTransition = ScreenTransitionRightInLeftOutPop()\n    )\n)\n```\n\n#### 响应系统返回\n\n##### Android\n\n在 Compose Screen 初始化时，传入 OnBackPressedDispatcherOwner, 就可以响应系统返回按键。\n\n##### Desktop\n\n可以通过 enableEscBack 来开启关闭 Compose Screen 响应 ESC 按键返回\n\n#### 横竖屏 UI 适配\n\n```kotlin\nval windowSizeOwner = LocalScreenWindowSizeOwner.current\nval windowWidth = remember {\n    windowSizeOwner.getWindowHolder().size.value.width.toInt()\n}\nval windowHeight = remember {\n    windowSizeOwner.getWindowHolder().size.value.height.toInt()\n}\nval windowSizeClass = remember {\n    windowSizeOwner.getWindowHolder().sizeClass.value\n}\n// 具体参考 https://developer.android.com/jetpack/compose/layouts/adaptive\nwhen (windowSizeClass) {\n    ScreenWindowSizeClass.Compact -\u003e {}\n    ScreenWindowSizeClass.Medium -\u003e {}\n    ScreenWindowSizeClass.Expanded -\u003e {}\n}\n```\n\n#### Android 异常状态恢复\n\n目前已自动处理了 Android 横竖屏切换或者配置变化下导致的异常状态恢复\n\n# 感谢\n\n- https://developer.android.com/jetpack/compose/navigation\n- https://github.com/bytedance/scene\n- https://github.com/olshevski/compose-navigation-reimagined\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsucclz123%2Fcompose-screen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsucclz123%2Fcompose-screen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsucclz123%2Fcompose-screen/lists"}