前言
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 lt.dygzs@qq.com
* 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)
如果大佬们有什么问题的话可以评论