编写UI时,无论是Vue/React这些前端框架,或者是Android/iOS开发,往往都会将页面UI分模块,然后每个UI模块封装成独立的UI组件,以达到UI代码复用和UI逻辑分治的目的。Kuikly也是如此,Kuikly封装组件的手段是使用ComposeView组合组件。接下来就跟着Kuikly详细的官方教程学习怎么封装组件:https://kuikly.woa.com/%E5%BC%80%E5%8F%91%E6%96%87%E6%A1%A3/compose-view.html#%E5%A6%82%E4%BD%95%E5%B0%81%E8%A3%85composeview
以Title Bar为例,首先新建一个类并继承ComposeView。
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()
接着我们实现NavigationBarView的UI,NavigationBarView左边有一个返回箭头,中间有一个title
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后,我们需要提供一个声明式方法给外部使用
internal fun ViewContainer<*, *>.NavBar(init: NavigationBarView.() -> Unit) {
addChild(NavigationBarView(), init)
}
在上述代码中,我们在ViewContainer扩展了NavBar方法, 并传入NavigationBarView的初始化闭包, 在方法内, 调用addChild, 把NavigationBarView实例和初始化闭包传入
外部调用NavBar方法即可将title bar组件添加到UI结构上
@Page("1")
internal class TestPage : BasePager() {
override fun body(): ViewBuilder {
val ctx = this
return {
NavBar { }
}
}
}
一个组件不仅仅只有UI界面,还有数据的流动。在NavigationBarView中,我们的标题的写死的,如果我们想使用从外部传入的标题,应该怎么做呢?
每个组合组件都有一个Attr类,代表组件自身的属性,让外部在调用组合组件时,配置组合组件的参数。
首先先定义一个类并继承ComposeAttr,声明title变量
internal class NavBarAttr : ComposeAttr() {
var title = ""
}
回到NavigationBarView中,将ComposeView<ComposeAttr, ComposeEvent>换成ComposeView<NavBarAttr, ComposeEvent>
并在createAttr()方法中返回NavBarAttr,最后将NavBarAttr中的title设置给Text组件
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的属性
@Page("1")
internal class TestPage : BasePager() {
private var translateAnimationFlag by observable(false)
override fun body(): ViewBuilder {
val ctx = this
return {
NavBar {
attr {
title = "外部传入的标题"
}
}
}
}
}
属性可以自定义,事件自然也可以自定义,我们来看看怎么定义事件
先新建一个类并继承ComposeEvent,并定义backIconClick方法
internal class NavBarEvent : ComposeEvent() {
var clickHandler: (() -> Unit)? = null
fun backIconClick(handler: () -> Unit) {
clickHandler = handler
}
}
和自定义属性一样,这里也需要把NavBarEvent传入NavBarView中,同时在点击事件触发时,通知外部
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组件的返回箭头点击事件
internal class TestPage : BasePager() {
override fun body(): ViewBuilder {
val ctx = this
return {
NavBar {
attr {
title = "外部传入的标题"
}
event {
backIconClick {
// 返回键点击事件
}
}
}
}
}
}
通过在继承ComposeView的子类重写这些方法,就可以在指定组件在什么时候干什么事了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。