kuikly-expand-view について
kuikly-expand-viewは、Kuikly開発者向けのカスタムView実装ガイドです。Kuikly側のAPI定義から、必要なプラットフォームでのネイティブ実装と登録までを扱います。
主な機能
- 01viewName、属性、イベントの定義
- 02宣言的API拡張の作成
- 03ネイティブ側での属性とメソッド処理
- 04対象プラットフォームのみ実装
- 05ViewRefによるインスタンス取得
活用シーン
- 01Kuiklyページ向けカスタムUIコンポーネントの作成
- 02既存のネイティブコンポーネントの再利用
- 03ネイティブイベントとメソッドのKuikly連携
- 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 つの要素で構成されます:
viewName:コンポーネントに対応するネイティブコンポーネントの名前Attr:コンポーネントの属性。コンポーネントが持つ属性を指定しますEvent:ネイティブコンポーネントから送信されるイベントを受け取りますメソッド:コンポーネント自体がサポートするメソッド。最終的には Native 側で実装します
手順:
DeclarativeBaseView<XxxAttr, XxxEvent>を継承する View クラスを新規作成しますviewName()、createAttr()、createEvent()メソッドを実装しますAttrを継承するAttrクラスを定義し、属性メソッドを追加しますEventを継承するEventクラスを定義し、イベント登録メソッドを追加します- 宣言型 API の拡張関数を記述します
- 業務コードでコンポーネントを使用します
手順 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 を実装すればよく、すべてのプラットフォームで実装する必要はありません。
手順:
- サポートする対象プラットフォーム(Android/iOS/鸿蒙/H5/小程序)を決定します。
- 対象プラットフォームのホストプロジェクトで、対応する View クラスを作成します。
setPropメソッドを実装して、属性とイベントを処理します。callメソッドを実装して、メソッド呼び出しを処理します。- View を Kuikly フレームワークに登録します。
各プラットフォームの実装の詳細は VIEW_IMPLEMENT.md を参照してください。
クイックリファレンス:各プラットフォームの View 基底クラスと登録方法
| プラットフォーム | 基底クラス/プロトコル | 登録方法 | 注意事項 |
|---|---|---|---|
| Android | IKuiklyRenderViewExport | registerExternalRenderView 内で renderViewExport(name) { View(ctx) } | ネイティブ View を継承し、インターフェースを実装します |
| iOS | KuiklyRenderViewExportProtocol | クラス名は viewName と一致する必要があります(実行時に動的作成) | 属性メソッド名は setCss_xxx、メソッド名は css_xxx にします |
| 鸿蒙 (ArkTS) | KuiklyRenderBaseView | getCustomRenderViewCreatorRegisterMap または getCustomRenderViewCreatorRegisterMapV2 内で登録します | createArkUIView() を実装して ComponentContent を返す必要があります |
| H5 | IKuiklyRenderViewExport | registerExternalRenderView 内で renderViewExport(name) { View() } | ele プロパティをオーバーライドして DOM 要素を返します |
| 小程序 | IKuiklyRenderViewExport | registerExternalRenderView + Transform.addComponentsAlias + base.wxml テンプレート | MiniXxxElement を作成し、テンプレートを設定する必要があります |
Native 側の setProp がサポートするデータ型
| Kuikly 側の型 | Native 側で受け取る型 |
|---|---|
String | String / NSString |
Int / Float / Double | 対応する基本型 / NSNumber |
Boolean | Boolean / 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 のコールバック内で呼び出す必要があります |
コメント
Markdown 対応