从0使用Kuikly框架写一个小红书Demo-Day3

三、 ComposeView组合组件及其生命周期详解

编写UI时,无论是Vue/React这些前端框架,或者是Android/iOS开发,往往都会将页面UI分模块,然后每个UI模块封装成独立的UI组件,以达到UI代码复用和UI逻辑分治的目的。Kuikly也是如此,Kuikly封装组件的手段是使用ComposeView组合组件。接下来就跟着Kuikly详细的官方教程学习怎么封装组件:kuikly.woa.com/%E5%BC%80%E...

3.1 封装组件

以Title Bar为例,首先新建一个类并继承ComposeView。

kotlin 复制代码
internal class NavigationBarView : ComposeView<ComposeAttr, ComposeEvent>() {
 
    override fun body(): ViewBuilder {
    }
 
    override fun createAttr(): ComposeAttr {
        return ComposeAttr()
    }
 
    override fun createEvent(): ComposeEvent {
        return ComposeEvent()
    }
 
}

在NavigationBarView中,我们需要实现三个方法:body()、createAttr()、createEvent()

  • body() : 组件UI界面写在这里面,
  • createAttr() : 定义组件有哪些属性
  • createEvent() : 定义组件有哪些事件

接着我们实现NavigationBarView的UI,NavigationBarView左边有一个返回箭头,中间有一个title

kotlin 复制代码
internal class NavigationBarView : ComposeView<ComposeAttr, ComposeEvent>() {
    override fun createAttr(): ComposeAttr {
        return ComposeAttr()
    }
 
    override fun createEvent(): ComposeEvent {
        return ComposeEvent()
    }
 
    override fun body(): ViewBuilder {
        return {
 
            View {
                attr {
                    size(pagerData.pageViewWidth, 44f)
                    marginTop(pagerData.statusBarHeight)
                    allCenter()
                    backgroundColor(Color.GRAY)
                }
 
                Image {
                    attr {
                        size(16f, 16f)
                        src(BASE_64)
                        resizeContain()
                        absolutePosition(left = 15f, top = (44f - 16f) / 2)
                    }
                }
 
                Text {
                    attr {
                        fontWeightBold()
                        fontSize(16f)
                        text("这是标题栏")
                    }
                }
 
            }
        }
    }
 
    companion object {
        private const val BASE_64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAASBAMAAAB/WzlGAAAAElBMVEUAAAAAAAAAAAAAAAAAAAAAAADgKxmiAAAABXRSTlMAIN/PELVZAGcAAAAkSURBVAjXYwABQTDJqCQAooSCHUAcVROCHBiFECTMhVoEtRYA6UMHzQlOjQIAAAAASUVORK5CYII="
    }
 
}
 

实现完UI后,我们需要提供一个声明式方法给外部使用

kotlin 复制代码
internal fun ViewContainer<*, *>.NavBar(init: NavigationBarView.() -> Unit) {
    addChild(NavigationBarView(), init)
}

在上述代码中,我们在ViewContainer扩展了NavBar方法, 并传入NavigationBarView的初始化闭包, 在方法内, 调用addChild, 把NavigationBarView实例和初始化闭包传入

外部调用NavBar方法即可将title bar组件添加到UI结构上

kotlin 复制代码
@Page("1")
internal class TestPage : BasePager() {
 
    override fun body(): ViewBuilder {
        val ctx = this
        return {
            NavBar {  }
        }
    }
 
}

3.2 定义组件的属性

一个组件不仅仅只有UI界面,还有数据的流动。在NavigationBarView中,我们的标题的写死的,如果我们想使用从外部传入的标题,应该怎么做呢?

每个组合组件都有一个Attr类,代表组件自身的属性,让外部在调用组合组件时,配置组合组件的参数。

首先先定义一个类并继承ComposeAttr,声明title变量

kotlin 复制代码
internal class NavBarAttr : ComposeAttr() {
    
    var title = ""
    
}

回到NavigationBarView中,将ComposeView<ComposeAttr, ComposeEvent>换成ComposeView<NavBarAttr, ComposeEvent>

并在createAttr()方法中返回NavBarAttr,最后将NavBarAttr中的title设置给Text组件

kotlin 复制代码
internal class NavigationBarView : ComposeView<NavBarAttr, ComposeEvent>() {
 
    override fun createAttr(): NavBarAttr {
        return NavBarAttr()
    }
 
    override fun createEvent(): ComposeEvent {
        return ComposeEvent()
    }
 
    override fun body(): ViewBuilder {
        val ctx = this
        return {
 
            View {
                attr {
                    size(pagerData.pageViewWidth, 44f)
                    marginTop(pagerData.statusBarHeight)
                    allCenter()
                    backgroundColor(Color.GRAY)
                }
 
                Image {
                    attr {
                        size(16f, 16f)
                        src(BASE_64)
                        resizeContain()
                        absolutePosition(left = 15f, top = (44f - 16f) / 2)
                    }
                }
 
                Text {
                    attr {
                        fontWeightBold()
                        fontSize(16f)
                        text(ctx.attr.title)
                    }
                }
 
            }
        }
    }
 
    companion object {
        private const val BASE_64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAASBAMAAAB/WzlGAAAAElBMVEUAAAAAAAAAAAAAAAAAAAAAAADgKxmiAAAABXRSTlMAIN/PELVZAGcAAAAkSURBVAjXYwABQTDJqCQAooSCHUAcVROCHBiFECTMhVoEtRYA6UMHzQlOjQIAAAAASUVORK5CYII="
    }
 
}

`

外部在使用NavBar时, 可在attr{}中,传入title的属性

kotlin 复制代码
@Page("1")
internal class TestPage : BasePager() {
 
    private var translateAnimationFlag by observable(false)
 
    override fun body(): ViewBuilder {
        val ctx = this
        return {
            NavBar {
                attr {
                    title = "外部传入的标题"
                }
            }
        }
    }
}

3.3 定义组件的事件

属性可以自定义,事件自然也可以自定义,我们来看看怎么定义事件

先新建一个类并继承ComposeEvent,并定义backIconClick方法

kotlin 复制代码
internal class NavBarEvent : ComposeEvent() {
    
    var clickHandler: (() -> Unit)? = null
    
    fun backIconClick(handler: () -> Unit) {
        clickHandler = handler
    }
}

和自定义属性一样,这里也需要把NavBarEvent传入NavBarView中,同时在点击事件触发时,通知外部

kotlin 复制代码
internal class NavigationBarView : ComposeView<NavBarAttr, NavBarEvent>() {
 
    override fun createAttr(): NavBarAttr {
        return NavBarAttr()
    }
 
    override fun createEvent(): NavBarEvent {
        return NavBarEvent()
    }
 
    override fun body(): ViewBuilder {
        val ctx = this
        return {
 
            View {
                attr {
                    size(pagerData.pageViewWidth, 44f)
                    marginTop(pagerData.statusBarHeight)
                    allCenter()
                    backgroundColor(Color.GRAY)
                }
 
                Image {
                    attr {
                        size(16f, 16f)
                        src(BASE_64)
                        resizeContain()
                        absolutePosition(left = 15f, top = (44f - 16f) / 2)
                    }
                    
                    event { 
                        click { 
                            ctx.event.clickHandler?.invoke() // 回调给外部
                        }
                    }
                }
 
                Text {
                    attr {
                        fontWeightBold()
                        fontSize(16f)
                        text(ctx.attr.title)
                    }
                }
 
            }
        }
    }
 
    companion object {
        private const val BASE_64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAASBAMAAAB/WzlGAAAAElBMVEUAAAAAAAAAAAAAAAAAAAAAAADgKxmiAAAABXRSTlMAIN/PELVZAGcAAAAkSURBVAjXYwABQTDJqCQAooSCHUAcVROCHBiFECTMhVoEtRYA6UMHzQlOjQIAAAAASUVORK5CYII="
    }
 
}

外部在使用NavBar时, 可在evnet{}中,监听NavBar组件的返回箭头点击事件

kotlin 复制代码
internal class TestPage : BasePager() {
 
    override fun body(): ViewBuilder {
        val ctx = this
        return {
            NavBar {
                attr {
                    title = "外部传入的标题"
                }
                
                event {
                    backIconClick {
                        // 返回键点击事件
                    }
                }
            }
        }
    }
}

3.4 ComposeView生命周期

  • created: ComposeView已经创建, 此方法会在body方法前调用

  • viewWillLoad: ComposeView的UI组件树即将创建, 此方法会在body方法前调用

  • viewDidLoad: ComposeView的UI组件树已经创建好, 此方法会在body方法之后调用

  • viewDidLayout: ComposeView的UI组件树已经测量完毕,可以在此方法执行一些依赖组件大小的操作,例如开始启动动画

  • viewWillUnload: ComposeView即将被移除

  • viewDidUnload: ComposeView已经被移除

  • viewDestroyed: ComposeView已经被销毁

通过在继承ComposeView的子类重写这些方法,就可以在指定组件在什么时候干什么事了。

相关推荐
我有与与症2 天前
从0使用Kuikly框架写一个小红书Demo-Day2
客户端
我有与与症2 天前
从0使用Kuikly框架写一个小红书Demo-Day1
客户端
赴3353 天前
基于pth模型文件,使用flask库将服务端部署到开发者电脑
人工智能·flask·客户端·模型部署·服务端
程序员老刘4 天前
2025年Flutter状态管理新趋势:AI友好度成为技术选型第一标准
flutter·ai编程·客户端
奔跑吧邓邓子8 天前
【C++实战(63)】C++ 网络编程实战:UDP客户端与服务端的奥秘之旅
网络·c++·udp·实战·客户端·服务端
程序员老刘15 天前
Flutter版本选择指南:避坑3.27 | 2025年9月
flutter·客户端
charlie11451419119 天前
Chrome View渲染机制学习小记
前端·chrome·学习·渲染·gpu·客户端
程序员老刘24 天前
跨平台开发地图:客户端技术选型指南 | 2025年9月
flutter·客户端
却尘1 个月前
Server Actions 深度剖析(2):缓存管理与重新验证,如何用一行代码干掉整个客户端状态层
前端·客户端·next.js