mcpField
K
kuikly-expand-view

kuikly-expand-view

github.com/tencent-tds開発134439 回インストール11 週間前に更新
リポジトリ

kuikly-expand-view について

kuikly-expand-viewは、Kuikly開発者向けのカスタムView実装ガイドです。Kuikly側のAPI定義から、必要なプラットフォームでのネイティブ実装と登録までを扱います。

主な機能

  1. 01viewName、属性、イベントの定義
  2. 02宣言的API拡張の作成
  3. 03ネイティブ側での属性とメソッド処理
  4. 04対象プラットフォームのみ実装
  5. 05ViewRefによるインスタンス取得

活用シーン

  1. 01Kuiklyページ向けカスタムUIコンポーネントの作成
  2. 02既存のネイティブコンポーネントの再利用
  3. 03ネイティブイベントとメソッドのKuikly連携
  4. 04必要なプラットフォームでの描画実装

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/tencent-tds/kuiklyui-ai --skill kuikly-expand-view

インストール後、Claude Code で/kuikly-expand-viewを入力して読み込まれたか確認します。

同梱ファイルreferences/VIEW_IMPLEMENT.md

詳細

目次

コアガイドライン

  • View はクロスプラットフォーム UI コンポーネントの共通インターフェースです: Kuikly には一般的な View(Text、Image、List など)が用意されています。カスタム View は、既存のネイティブ UI コンポーネントの再利用や特別な要件への対応に使用します。
  • カスタム View は両側で実装する必要があります: Kuikly 側でコンポーネントの構造(viewName、Attr、Event)を定義し、Native 側(Android/iOS/鸿蒙/H5/小程序)で具体的なレンダリングロジックを実装し、viewName で関連付けます。
  • コンポーネント名はすべてのプラットフォームで統一する必要があります: Kuikly 側の viewName() の戻り値は、Native 側で登録した名前と完全に一致する必要があります。
  • 属性とイベントは setProp メソッドを使用します: Native 側は setProp(propKey, propValue) を通じて、Kuikly 側で設定された属性とイベントを受け取ります。
  • メソッド呼び出しには call メソッドを使用します: Native 側は call(method, params, callback) を通じて Kuikly 側からのメソッド呼び出しに応答します。

ワークフロー:Expand View の作成(Kuikly 側)

このワークフローでは、Kuikly(Kotlin)側で Expand View を作成します。

Kuikly コンポーネントは次の 4 つの要素で構成されます:

  1. viewName:コンポーネントに対応するネイティブコンポーネントの名前
  2. Attr:コンポーネントの属性。コンポーネントが持つ属性を指定します
  3. Event:ネイティブコンポーネントから送信されるイベントを受け取ります
  4. メソッド:コンポーネント自体がサポートするメソッド。最終的には Native 側で実装します

手順:

  1. DeclarativeBaseView<XxxAttr, XxxEvent> を継承する View クラスを新規作成します
  2. viewName()、createAttr()、createEvent() メソッドを実装します
  3. Attr を継承する Attr クラスを定義し、属性メソッドを追加します
  4. Event を継承する Event クラスを定義し、イベント登録メソッドを追加します
  5. 宣言型 API の拡張関数を記述します
  6. 業務コードでコンポーネントを使用します
手順 1:View クラスを定義する
import com.tencent.kuikly.core.base.DeclarativeBaseView

class MyImageView : DeclarativeBaseView<MyImageAttr, MyImageEvent>() {

    override fun createAttr(): MyImageAttr {
        return MyImageAttr()
    }

    override fun createEvent(): MyImageEvent {
        return MyImageEvent()
    }

    // 返回 Native 侧注册的组件名
    override fun viewName(): String {
        return "HRImageView"
    }
    
    // 组件方法(可选),实际实现在 Native 侧
    fun test() {
        performTaskWhenRenderViewDidLoad {
            renderView?.callMethod("test", "params")
        }
    }
}
手順 2:Attr クラスを定義する

Attr は、コンポーネントがサポートする属性の集合を表します。

import com.tencent.kuikly.core.base.Attr

class MyImageAttr : Attr() {

    /**
     * 设置图片数据源
     * @param src 图片 URL
     * @return this(支持链式调用)
     */
    fun src(src: String): MyImageAttr {
        "src" with src  // 将属性透传给原生组件
        return this
    }

    /**
     * 设置占位图
     */
    fun placeholder(url: String): MyImageAttr {
        "placeholder" with url
        return this
    }

    /**
     * 设置缩放模式
     */
    fun scaleType(type: String): MyImageAttr {
        "scaleType" with type
        return this
    }
}
手順 3:Event クラスを定義する

Event は、コンポーネントがサポートするイベントを表します。

import com.tencent.kuikly.core.base.event.Event
import com.tencent.kuikly.core.nvi.serialization.json.JSONObject

class MyImageEvent : Event() {

    /**
     * 图片加载成功回调
     */
    fun loadSuccess(handler: (LoadSuccessParams) -> Unit) {
        register(LOAD_SUCCESS) {
            handler(LoadSuccessParams.decode(it))
        }
    }

    /**
     * 图片加载失败回调
     */
    fun loadError(handler: (LoadErrorParams) -> Unit) {
        register(LOAD_ERROR) {
            handler(LoadErrorParams.decode(it))
        }
    }

    companion object {
        const val LOAD_SUCCESS = "loadSuccess"
        const val LOAD_ERROR = "loadError"
    }
}

// 事件参数解析类
data class LoadSuccessParams(
    val src: String,
    val width: Int,
    val height: Int
) {
    companion object {
        fun decode(params: Any?): LoadSuccessParams {
            val tempParams = params as? JSONObject ?: JSONObject()
            return LoadSuccessParams(
                src = tempParams.optString("src", ""),
                width = tempParams.optInt("width", 0),
                height = tempParams.optInt("height", 0)
            )
        }
    }
}

data class LoadErrorParams(
    val src: String,
    val errorCode: Int
) {
    companion object {
        fun decode(params: Any?): LoadErrorParams {
            val tempParams = params as? JSONObject ?: JSONObject()
            return LoadErrorParams(
                src = tempParams.optString("src", ""),
                errorCode = tempParams.optInt("errorCode", 0)
            )
        }
    }
}
手順 4:コンポーネントのメソッド(任意)

コンポーネントのメソッドは Kuikly 側で公開する API で、実際の処理は Native 側で実装します。

class MyImageView : DeclarativeBaseView<MyImageAttr, MyImageEvent>() {
    // ...
    
    /**
     * 重新加载图片(无返回值)
     */
    fun reload() {
        performTaskWhenRenderViewDidLoad {
            renderView?.callMethod("reload", null)
        }
    }
    
    /**
     * 获取图片信息(异步回调)
     */
    fun getImageInfo(callback: (width: Int, height: Int) -> Unit) {
        performTaskWhenRenderViewDidLoad {
            renderView?.callMethod("getImageInfo", null) { result ->
                val json = result as? JSONObject
                callback(json?.optInt("width") ?: 0, json?.optInt("height") ?: 0)
            }
        }
    }
}

⚠️ 注意:

  • View のメソッドは非同期コールバックの結果をサポートします。例:renderView?.callMethod("method", "params", callback)。ただし、同期的な戻り値はサポートしません。
  • View のメソッドはバイナリデータの受け渡しをサポートしません。画像などのバイナリコンテンツを転送する場合は、Base64 にエンコードして JSON 形式で渡すか、Module メソッドを使用してください。
手順 5:宣言型 API を記述する
import com.tencent.kuikly.core.base.ViewContainer

fun ViewContainer<*, *>.MyImage(init: MyImageView.() -> Unit) {
    addChild(MyImageView(), init)
}
手順 6:業務コードで使用する
override fun body(): ViewBuilder {
    val ctx = this
    return {
        MyImage {
            attr {
                size(176f, 132f)
                src("https://example.com/image.png")
                placeholder("https://example.com/placeholder.png")
            }
            event {
                loadSuccess { params ->
                    println("图片加载成功: ${params.src}, 尺寸: ${params.width}x${params.height}")
                }
                loadError { params ->
                    println("图片加载失败: ${params.errorCode}")
                }
            }
        }
    }
}
ViewRef を使用してコンポーネント参照を取得する

ViewRef を使用するとコンポーネントインスタンスを取得でき、Pager の別の場所からコンポーネントのメソッドを呼び出せます。

@Page("MyPage")
class MyPage : Pager() {
    
    // 声明 ViewRef
    private val imageRef = ViewRef<MyImageView>()
    
    override fun body(): ViewBuilder {
        return {
            MyImage {
                // 绑定 ref
                ref(imageRef)
                attr {
                    src("https://example.com/image.png")
                }
            }
            
            Button {
                attr { title("重新加载") }
                event {
                    click {
                        // 通过 ref 调用方法
                        imageRef.view?.reload()
                    }
                }
            }
        }
    }
}

ワークフロー:Native 側 View の実装

このワークフローでは、Expand View の Native 側を実装します。

前提: 業務上必要なプラットフォームでのみ Native 側 View を実装すればよく、すべてのプラットフォームで実装する必要はありません。

手順:

  1. サポートする対象プラットフォーム(Android/iOS/鸿蒙/H5/小程序)を決定します。
  2. 対象プラットフォームのホストプロジェクトで、対応する View クラスを作成します。
  3. setProp メソッドを実装して、属性とイベントを処理します。
  4. call メソッドを実装して、メソッド呼び出しを処理します。
  5. View を Kuikly フレームワークに登録します。

各プラットフォームの実装の詳細は VIEW_IMPLEMENT.md を参照してください。

クイックリファレンス:各プラットフォームの View 基底クラスと登録方法

プラットフォーム基底クラス/プロトコル登録方法注意事項
AndroidIKuiklyRenderViewExportregisterExternalRenderView 内で renderViewExport(name) { View(ctx) }ネイティブ View を継承し、インターフェースを実装します
iOSKuiklyRenderViewExportProtocolクラス名は viewName と一致する必要があります(実行時に動的作成)属性メソッド名は setCss_xxx、メソッド名は css_xxx にします
鸿蒙 (ArkTS)KuiklyRenderBaseViewgetCustomRenderViewCreatorRegisterMap または getCustomRenderViewCreatorRegisterMapV2 内で登録しますcreateArkUIView() を実装して ComponentContent を返す必要があります
H5IKuiklyRenderViewExportregisterExternalRenderView 内で renderViewExport(name) { View() }ele プロパティをオーバーライドして DOM 要素を返します
小程序IKuiklyRenderViewExportregisterExternalRenderView + Transform.addComponentsAlias + base.wxml テンプレートMiniXxxElement を作成し、テンプレートを設定する必要があります
Native 側の setProp がサポートするデータ型
Kuikly 側の型Native 側で受け取る型
StringString / NSString
Int / Float / Double対応する基本型 / NSNumber
BooleanBoolean / BOOL
Event コールバックKuiklyRenderCallback
イベントの発火メカニズム

Native 側では、イベントは KuiklyRenderCallback を通じて Kuikly 側にコールバックされます:

// 保存回调
private var loadSuccessCallback: KuiklyRenderCallback? = null

override fun setProp(propKey: String, propValue: Any): Boolean {
    return when (propKey) {
        "loadSuccess" -> {
            loadSuccessCallback = propValue as KuiklyRenderCallback
            true
        }
        else -> super.setProp(propKey, propValue)
    }
}

// 触发回调
private fun onImageLoaded(src: String, width: Int, height: Int) {
    loadSuccessCallback?.invoke(mapOf(
        "src" to src,
        "width" to width,
        "height" to height
    ))
}

よくある落とし穴と正しい方法

❌ 誤った方法✅ 正しい方法
View の名前が Kuikly 側と Native 側で一致していないviewName() の戻り値が Native 側の登録名と完全に一致するようにします
カスタム View に幅と高さを設定していないため表示されないカスタム View をクロスプラットフォームで使用する場合は、幅と高さ(例:size(w, h))を明示的に設定する必要があります。設定しないと表示されないことがあります
iOS 側の View クラス名が Kuikly 側の viewName と一致していないiOS ではクラス名を使って View を動的に作成するため、クラス名は viewName() と一致する必要があります
iOS 側で Swift を使って実装しているが @objc アノテーションを付けていないSwift で実装した View には @objc または @objcMembers を付ける必要があります
鸿蒙 側で createArkUIView() の実装を忘れている鸿蒙 側では、このメソッドを実装して ComponentContent を返す必要があります
Native 側でカスタム View の登録を忘れているカスタム View は登録してからでないと使用できません
performTaskWhenRenderViewDidLoad の外で renderView を呼び出しているView のメソッドは performTaskWhenRenderViewDidLoad のコールバック内で呼び出す必要があります

コメント