SuperAPI AI Directory

kuikly-compose-interop-dsl

Coding & development

View repository

Updated 10-15 23:39

About this skill

Mixing Compose DSL with Kuikly DSL components

⚠️ Note: This skill only applies to mixing Kuikly DSL in Compose DSL(i.e., embedding Kuikly DSL components in Compose pages),does not supportthe reverse, mixing Compose DSL in Kuikly DSL.

Contents

  • ComposeContainer page setup
  • MakeKuiklyComposeNode API (atomic / container)
  • Key constraints and common errors
  • Using Kuikly Module in Compose
  • Detailed reference documentation

ComposeContainer page setup

Compose pages inherit ComposeContainer(i.e., Pager) and call in willInit() call in setContent {}:

import com.tencent.kuikly.compose.ComposeContainer
import com.tencent.kuikly.compose.setContent
import com.tencent.kuikly.core.annotations.Page

@Page("myPage")
class MyPage : ComposeContainer() {
    override fun willInit() {
        super.willInit()
        setContent { MyScreen() }
    }
}

ComposeContainer inherits from Kuikly Core's Pager, with a unified cross-platform page lifecycle (willInit / created / pageDidAppear / pageDidDisappear / pageWillDestroy)。

MakeKuiklyComposeNode API

bridging entry, embedding Kuikly DSL components into the Compose render tree. Two overloads:

Atomic components (no child nodes)

Applies to DeclarativeBaseView subclasses (self-rendering components such as Video, maps):

@Composable
fun <T : DeclarativeBaseView<*, *>> MakeKuiklyComposeNode(
    factory: () -> T,
    modifier: Modifier,
    viewInit: T.() -> Unit = {},       // 创建时调用一次
    viewUpdate: (T) -> Unit = {},      // 每次重组时调用
    measurePolicy: MeasurePolicy = KuiklyDefaultMeasurePolicy
)

Minimal example(wrapping VideoView):

import androidx.compose.runtime.Composable
import com.tencent.kuikly.compose.extension.MakeKuiklyComposeNode
import com.tencent.kuikly.compose.ui.Modifier
import com.tencent.kuikly.core.views.VideoPlayControl
import com.tencent.kuikly.core.views.VideoView

@Composable
fun Video(src: String, playControl: VideoPlayControl, modifier: Modifier = Modifier) {
    MakeKuiklyComposeNode<VideoView>(
        factory = { VideoView() },
        modifier = modifier,
        viewInit = { getViewAttr().run { src(src); playControl(playControl) } },
        viewUpdate = { it.getViewAttr().run { src(src); playControl(playControl) } },
    )
}

Container components (with child nodes)

Applies to ViewContainer subclasses, can mount Compose child nodes:

@Composable
fun <T : DeclarativeBaseView<*, *>> MakeKuiklyComposeNode(
    factory: () -> T,
    modifier: Modifier,
    content: @Composable () -> Unit,   // 子内容插槽
    viewInit: T.() -> Unit = {},
    viewUpdate: (T) -> Unit = {},
    measurePolicy: MeasurePolicy = DefaultColumnMeasurePolicy
)

Minimal example(wrapping a container card):

import com.tencent.kuikly.core.base.ViewContainer
import com.tencent.kuikly.core.base.ContainerAttr
import com.tencent.kuikly.core.base.Event
import com.tencent.kuikly.core.base.ViewConst

class KuiklyCard : ViewContainer<ContainerAttr, Event>() {
    override fun createAttr() = ContainerAttr()
    override fun createEvent() = Event()
    override fun viewName() = ViewConst.TYPE_VIEW

    fun setup(cornerRadius: Float = 12f, onClick: (() -> Unit)? = null) {
        attr { borderRadius(cornerRadius) }
        onClick?.let { event { click { onClick() } } }
    }
}

@Composable
fun KuiklyCard(
    modifier: Modifier = Modifier,
    cornerRadius: Float = 12f,
    onClick: (() -> Unit)? = null,
    content: @Composable () -> Unit,
) {
    MakeKuiklyComposeNode<KuiklyCard>(
        factory = { KuiklyCard() },
        modifier = modifier,
        viewInit = { setup(cornerRadius, onClick) },
        viewUpdate = { it.setup(cornerRadius, onClick) },
        content = content,
    )
}

Key constraints and common errors

Choosing the factory base class

Scenario Base class
Atomic components (no child nodes) DeclarativeBaseView
Container components (with child nodes) ViewContainer
❌ Forbidden ComposeView

❌ Forbidden to pass ComposeView subclasses to factory

ComposeView 's flattening optimization causes layout frame loss and the view to be invisible:

// ❌ 编译通过但运行时不可见
class MyView : ComposeView<ComposeAttr, ComposeEvent>() { ... }
MakeKuiklyComposeNode<MyView>(factory = { MyView() }, ...)

// ✅ 原子组件用 DeclarativeBaseView
// ✅ 容器组件用 ViewContainer

viewUpdate must be updated in sync

viewInit is called only once at creation; properties and event callbacks that change with Compose statemustalso be set in viewUpdate , otherwise they will not be updated after recomposition.

Using Kuikly Module in Compose

Via LocalActivity.current.getPager() obtain the Pager instance, then call acquireModule:

import com.tencent.kuikly.compose.ui.platform.LocalActivity
import com.tencent.kuikly.core.pager.Pager
import com.tencent.kuikly.core.module.RouterModule

@Composable
fun MyScreen() {
    val pager = LocalActivity.current.getPager() as Pager
    val router = pager.acquireModule<RouterModule>(RouterModule.MODULE_NAME)
    // 使用 router.openPage("targetPage", params) / router.closePage() 等
}

acquireModule throws an exception when not found;getModule returns null when not found.

Detailed reference

  • Component wrapping in detail(atomic/container, viewInit vs viewUpdate, error troubleshooting):COMPONENT_WRAPPING.md
  • Module usage details(Router / Notify / SP / PageData / custom Module):MODULE_USAGE.md