Giter Club home page Giter Club logo

compose-screen's Introduction

banner

介绍

一个简单并提供高度扩展功能的 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

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

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

// 创建 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()
    }
    ...
    
 }

导航

// 获取 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")

返回

screenNavigator.pop()
返回到某一页面
screenNavigator.popTo(screenName = "ZZZScreen")
返回并获得结果
val onResult = LocalScreenRecord.current.result
返回拦截
screenNavigator.pop(popOptions = PopOptions(popStackFinalInterceptor = { backstackList, _, _ ->
    backstackList.size > 10
}))

浮窗

弹窗


PopupScreen 层级高于 Screen,附属于当前绑定的 Group Screen。退出 Group Screen 时,PopupScreen 同时消失。

ScreenHost(screenNavigator = screenNavigator, rootScreenName = Manifest.MainScreen) {
    // register your popup screen
    popup(screenName = Manifest.DialogPopupScreen) {
            DialogPopupScreen(screenNavigator)
        }
    }

// show th dialog
screenNavigator.push(Manifest.DialogPopupScreen)
吐司


全局只有一个吐司,吐司永远在所有页面层级之上,切换页面不会导致吐司消失。

// 默认的吐司
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 同时消失。

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
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
// 绑定到当前 group screen 的 ViewModel,当 group screen 出栈的时候,该 ViewModel 被销毁
val viewModel = viewModel { YourViewModel() }
  • sharedViewModel
// XXX -> YYY,当 YYY 出栈的时候,sharedViewModel 将继续存在,当 XXX 也出栈的时候, sharedViewModel 才被销毁
@Composable
fun XXXScreen(){
    val sharedViewModel = sharedViewModel { YourViewModel() }
}

@Composable
fun YYYScreen(){
    val sharedViewModel = sharedViewModel { YourViewModel() }
}
  • globalViewModel
// 被绑定到 Screen Mananger 上的 ViewModel,全局唯一,只有 Screen Mananger 不在后才被销毁
val globalViewModel = globalViewModel { YourViewModel() }
Android ViewModel
// Android 平台独有,通过初始化时传入的 ViewModelStoreOwner,来获取或者生成 AndroidX 的 ViewModel.
val androidViewModel = androidViewModel { YourAndroidViewModel() }

动画

转场动画

框架内已经封装了几个常见转场动画,如下是右边进左边出的转场动画

screenNavigator.push(
    "your screen",
    pushOptions = PushOptions(
        pushTransition = ScreenTransitionRightInLeftOutPush(),
        popTransition = ScreenTransitionRightInLeftOutPop()
    )
)

响应系统返回

Android

在 Compose Screen 初始化时,传入 OnBackPressedDispatcherOwner, 就可以响应系统返回按键。

Desktop

可以通过 enableEscBack 来开启关闭 Compose Screen 响应 ESC 按键返回

横竖屏 UI 适配

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 横竖屏切换或者配置变化下导致的异常状态恢复

感谢

compose-screen's People

Contributors

succlz123 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.