三、 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的子类重写这些方法,就可以在指定组件在什么时候干什么事了。