Compose之跨平台Activity页面

前言

Compose(Jetpack+jb)是可以跨平台的

目前跨平台主流的页面导航方式一般有两种

一种是都在同一个页面内进行页面替换类型的导航,类似于单Activity,多Fragment

另一种是不同的页面在不同的页面载体上,类似多Activity

两种页面导航方式都可以使用,但我比较偏向于使用多Activity的方案(见仁见智)

分析

拿Compose跨Android和Desktop来举例

Android的载体有Activity,Fragment,Compose fun

Desktop的载体有Window,Compose fun

我们可以使用Kotlin expect来关联Android的Activity和Desktop的Compose fun(或Window),写一个统一的类BaseComposeActivity

这样BaseComposeActivity在Android中就映射为一个真正的Activity,而在Desktop中映射为一个Compose fun,方便我们进行页面导航

正文

我们先写一个最简单的BaseComposeActivity出来,然后后面有需求我们在加东西

common:

/**
 * creator: lt  2021/4/27  [email protected]
 * effect : 以Compose为根View的ba
 * warning:
 */
expect abstract class BaseComposeActivity() {

    /**
     * compose根布局,我们页面的Compose视图都在这个函数内写
     */
    @Composable
    actual abstract fun ComposeContent()
}

android:

actual abstract class BaseComposeActivity : AppCompatActivity() {

    @Composable
    actual abstract fun ComposeContent()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyTheme {
                ComposeContent()
            }
        }
    }
}

desktop:

actual abstract class BaseComposeActivity {

    @Composable
    actual abstract fun ComposeContent()
}

这样我们一个基本的BaseComposeActivity就完成了,因为Android继承了AppCompatActivity类,所以可以直接通过Android的startActivity来启动,通过finish来销毁

而Desktop我们可以通过自定义一个页面栈,通过观察,添加,删除来管理页面:

将desktop的BaseComposeActivity改成这样:

actual abstract class BaseComposeActivity {

    @Composable
    actual abstract fun ComposeContent()

    actual fun mFinish() {
        //移除页面(可以改为remove(this))
        _activityStack.removeLast()
    }

    actual fun jump(clazz: Class<out BaseComposeActivity>) {
        //跳转页面,往栈中加入新页面
        //ps:这里可以做各种传参,生命周期或启动模式等的处理,此篇就不在赘述
        _activityStack.add(clazz.newInstance())
    }

    companion object {
        //自定义的任务栈,可以被Compose所观察
        val _activityStack = mutableStateListOf<BaseComposeActivity>(MainActivity())
    }
}

最后给Desktop的Application(main函数)添加BaseComposeActivity支持

fun main(vararg args: String) {
    //desktop的根应用
    application {
        //将所有页面放在一个Window中,也可以稍加修改改为每个BaseComposeActivity一个Window
        Window(onCloseRequest = ::exitApplication) {
            MyTheme {
                //页面内容
                BaseComposeActivity._activityStack.forEachIndexed { index, baseActivity ->
                        //防止Compose生命周期变更导致的问题
                        key(baseActivity) {
                            Column(
                                //使栈顶的Activity有宽高,其他页面没有宽高,这样就可以有覆盖的效果了
                                if (index == 0)
                                    M.fillMaxSize()
                                        .background(Color.White)
                                else
                                    M.size(0.dp)
                            ) {
                                baseActivity.ComposeContent()
                            }
                        }
                }
            }
        }
    }
}

这样我们就封装好了一个跨平台的Activity

ps:后续出ios和web也可以类似如此的封装

我们可以直接在common中写Activity,比如:

class BannerActivity : BaseComposeActivity() {
    @Composable
    override fun ComposeContent() {
        val bannerState = rememberBannerState()
        Banner(
            colors.size,
            M.fillMaxSize(),
            bannerState = bannerState,
            autoScrollTime = 1000,
            orientation = Orientation.Vertical,
        ) {
        }
        //jump<BannerActivity>()
        //finish()
    }

}

desktop上的效果如下所示(Android和之前一样就不演示了): 

结语

当然跨平台的导航也可以使用单个页面内导航,可能对于Compose来说会更简单一点,但可能会少了一些灵活性

其实内部也可以将跨平台的toast和dialog封装到Activity中,如果你看懂了这篇文章,那对你来说应该也是很简单,下面的链接有示例

ps:完整代码可以参考(欢迎各位大佬star):ComposeViews(github)

如果大佬们有什么问题的话可以评论

猜你喜欢

转载自blog.csdn.net/qq_33505109/article/details/128812719