Skip to content

Commit 635dce5

Browse files
committed
feat(core/views): add TableView, TableRowView, TableCellView native DSL.
Signed-off-by: 林晨 (Leo Cheng) <leo-cheng@vip.qq.com> style(core/views): remove separator comments and add isRenderView note. Signed-off-by: 林晨 (Leo Cheng) <leo-cheng@vip.qq.com>
1 parent 0eadaed commit 635dce5

3 files changed

Lines changed: 375 additions & 1 deletion

File tree

core/src/commonMain/kotlin/com/tencent/kuikly/core/base/ViewConst.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,7 @@ object ViewConst {
5959
const val TYPE_VIDEO_VIEW = "KRVideoView"
6060
const val TYPE_MODAL_VIEW = "KRModalView"
6161

62-
}
62+
const val TYPE_TABLE = "KRTableView"
63+
const val TYPE_TABLE_ROW = "KRTableRowView"
64+
const val TYPE_TABLE_CELL = "KRTableCellView"
65+
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
* Tencent is pleased to support the open source community by making KuiklyUI
3+
* available.
4+
* Copyright (C) 2025 Tencent. All rights reserved.
5+
* Licensed under the License of KuiklyUI;
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
* https://github.com/Tencent-TDS/KuiklyUI/blob/main/LICENSE
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
package com.tencent.kuikly.core.views
17+
18+
import com.tencent.kuikly.core.base.Color
19+
import com.tencent.kuikly.core.base.ViewConst
20+
import com.tencent.kuikly.core.base.ViewContainer
21+
import com.tencent.kuikly.core.base.toInt
22+
import com.tencent.kuikly.core.log.KLog
23+
import com.tencent.kuikly.core.views.internal.GroupAttr
24+
import com.tencent.kuikly.core.views.internal.GroupEvent
25+
import com.tencent.kuikly.core.views.internal.GroupView
26+
27+
fun ViewContainer<*, *>.Table(init: TableView.() -> Unit) {
28+
addChild(TableView(), init)
29+
}
30+
31+
fun ViewContainer<*, *>.TableRow(init: TableRowView.() -> Unit) {
32+
addChild(TableRowView(), init)
33+
}
34+
35+
fun ViewContainer<*, *>.TableCell(init: TableCellView.() -> Unit) {
36+
addChild(TableCellView(), init)
37+
}
38+
39+
open class TableView : GroupView<TableAttr, TableEvent>() {
40+
41+
override fun createAttr(): TableAttr = TableAttr()
42+
43+
override fun createEvent(): TableEvent = TableEvent()
44+
45+
override fun viewName(): String = ViewConst.TYPE_TABLE
46+
47+
// Native table view (KRTableView) always requires its own native layer; excluding it
48+
// from flat-layer optimisation prevents silent rendering failures in scroll containers.
49+
override fun isRenderView(): Boolean = true
50+
51+
fun TableRow(init: TableRowView.() -> Unit) {
52+
addChild(TableRowView(), init)
53+
}
54+
}
55+
56+
open class TableAttr : GroupAttr() {
57+
58+
fun separatorColor(color: Color) {
59+
"separatorColor" with color.hexColor
60+
}
61+
62+
fun separatorHeight(height: Float) {
63+
"separatorHeight" with height
64+
}
65+
66+
fun allowsMultipleSelection(allow: Boolean) {
67+
"allowsMultipleSelection" with allow.toInt()
68+
}
69+
70+
fun allowsSelection(allow: Boolean) {
71+
"allowsSelection" with allow.toInt()
72+
}
73+
}
74+
75+
open class TableEvent : GroupEvent() {
76+
77+
fun rowClick(handler: (index: Int) -> Unit) {
78+
register("rowClick") { data ->
79+
val index = (data as? Number)?.toInt()
80+
if (index == null) {
81+
KLog.w("TableEvent", "rowClick: unexpected data type ${data?.let { it::class.simpleName }}")
82+
return@register
83+
}
84+
handler(index)
85+
}
86+
}
87+
88+
fun rowLongPress(handler: (index: Int) -> Unit) {
89+
register("rowLongPress") { data ->
90+
val index = (data as? Number)?.toInt()
91+
if (index == null) {
92+
KLog.w("TableEvent", "rowLongPress: unexpected data type ${data?.let { it::class.simpleName }}")
93+
return@register
94+
}
95+
handler(index)
96+
}
97+
}
98+
}
99+
100+
open class TableRowView : GroupView<TableRowAttr, TableRowEvent>() {
101+
102+
override fun createAttr(): TableRowAttr = TableRowAttr()
103+
104+
override fun createEvent(): TableRowEvent = TableRowEvent()
105+
106+
override fun viewName(): String = ViewConst.TYPE_TABLE_ROW
107+
108+
override fun isRenderView(): Boolean = true
109+
110+
fun TableCell(init: TableCellView.() -> Unit) {
111+
addChild(TableCellView(), init)
112+
}
113+
}
114+
115+
open class TableRowAttr : GroupAttr() {
116+
117+
fun rowHeight(height: Float) {
118+
"rowHeight" with height
119+
}
120+
121+
fun selectable(selectable: Boolean) {
122+
"selectable" with selectable.toInt()
123+
}
124+
}
125+
126+
open class TableRowEvent : GroupEvent() {
127+
128+
fun selected(handler: (index: Int) -> Unit) {
129+
register("selected") { data ->
130+
val index = (data as? Number)?.toInt()
131+
if (index == null) {
132+
KLog.w("TableRowEvent", "selected: unexpected data type ${data?.let { it::class.simpleName }}")
133+
return@register
134+
}
135+
handler(index)
136+
}
137+
}
138+
139+
fun deselected(handler: (index: Int) -> Unit) {
140+
register("deselected") { data ->
141+
val index = (data as? Number)?.toInt()
142+
if (index == null) {
143+
KLog.w("TableRowEvent", "deselected: unexpected data type ${data?.let { it::class.simpleName }}")
144+
return@register
145+
}
146+
handler(index)
147+
}
148+
}
149+
}
150+
151+
open class TableCellView : GroupView<TableCellAttr, TableCellEvent>() {
152+
153+
override fun createAttr(): TableCellAttr = TableCellAttr()
154+
155+
override fun createEvent(): TableCellEvent = TableCellEvent()
156+
157+
override fun viewName(): String = ViewConst.TYPE_TABLE_CELL
158+
159+
override fun isRenderView(): Boolean = true
160+
}
161+
162+
open class TableCellAttr : GroupAttr() {
163+
164+
fun columnSpan(span: Int) {
165+
"columnSpan" with span
166+
}
167+
}
168+
169+
open class TableCellEvent : GroupEvent()
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/*
2+
* Tencent is pleased to support the open source community by making KuiklyUI
3+
* available.
4+
* Copyright (C) 2025 Tencent. All rights reserved.
5+
* Licensed under the License of KuiklyUI;
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
* https://github.com/Tencent-TDS/KuiklyUI/blob/main/LICENSE
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
package com.tencent.kuikly.demo.pages.demo
17+
18+
import com.tencent.kuikly.core.annotations.Page
19+
import com.tencent.kuikly.core.base.Color
20+
import com.tencent.kuikly.core.base.ViewBuilder
21+
import com.tencent.kuikly.core.log.KLog
22+
import com.tencent.kuikly.core.views.Table
23+
import com.tencent.kuikly.core.views.TableCell
24+
import com.tencent.kuikly.core.views.TableRow
25+
import com.tencent.kuikly.core.views.Text
26+
import com.tencent.kuikly.core.views.View
27+
import com.tencent.kuikly.demo.pages.base.BasePager
28+
import com.tencent.kuikly.demo.pages.demo.base.NavBar
29+
30+
private data class TableItem(val name: String, val score: String, val grade: String)
31+
32+
@Page("TableViewDemoPage")
33+
internal class TableViewDemoPage : BasePager() {
34+
35+
private val items = listOf(
36+
TableItem("Alice", "95", "A"),
37+
TableItem("Bob", "82", "B"),
38+
TableItem("Carol", "78", "C+"),
39+
TableItem("Dave", "91", "A-"),
40+
TableItem("Eve", "67", "D+"),
41+
TableItem("Frank", "88", "B+"),
42+
TableItem("Grace", "74", "C"),
43+
TableItem("Henry", "99", "A+"),
44+
)
45+
46+
override fun body(): ViewBuilder {
47+
val ctx = this
48+
return {
49+
NavBar {
50+
attr {
51+
title = "TableView Demo"
52+
}
53+
}
54+
Table {
55+
attr {
56+
flex(1f)
57+
separatorColor(Color(0xFFE0E0E0L))
58+
separatorHeight(0.5f)
59+
allowsSelection(true)
60+
}
61+
event {
62+
rowClick { index ->
63+
KLog.i("TableViewDemo", "row clicked: $index")
64+
}
65+
}
66+
TableRow {
67+
attr {
68+
rowHeight(44f)
69+
backgroundColor(Color(0xFFF5F5F5L))
70+
flexDirectionRow()
71+
}
72+
TableCell {
73+
attr {
74+
flex(2f)
75+
justifyContentCenter()
76+
paddingLeft(16f)
77+
}
78+
Text {
79+
attr {
80+
fontSize(14f)
81+
color(Color(0xFF333333L))
82+
fontWeight700()
83+
text("Name")
84+
}
85+
}
86+
}
87+
TableCell {
88+
attr {
89+
flex(1f)
90+
justifyContentCenter()
91+
alignItemsCenter()
92+
}
93+
Text {
94+
attr {
95+
fontSize(14f)
96+
color(Color(0xFF333333L))
97+
fontWeight700()
98+
text("Score")
99+
}
100+
}
101+
}
102+
TableCell {
103+
attr {
104+
flex(1f)
105+
justifyContentCenter()
106+
alignItemsCenter()
107+
}
108+
Text {
109+
attr {
110+
fontSize(14f)
111+
color(Color(0xFF333333L))
112+
fontWeight700()
113+
text("Grade")
114+
}
115+
}
116+
}
117+
}
118+
ctx.items.forEachIndexed { index, item ->
119+
TableRow {
120+
attr {
121+
rowHeight(48f)
122+
flexDirectionRow()
123+
backgroundColor(
124+
if (index % 2 == 0) Color.WHITE else Color(0xFFFAFAFAL)
125+
)
126+
}
127+
event {
128+
click {
129+
KLog.i("TableViewDemo", "clicked item: ${item.name}")
130+
}
131+
selected { idx ->
132+
KLog.i("TableViewDemo", "row $idx selected: ${item.name}")
133+
}
134+
deselected { idx ->
135+
KLog.i("TableViewDemo", "row $idx deselected")
136+
}
137+
}
138+
TableCell {
139+
attr {
140+
flex(2f)
141+
justifyContentCenter()
142+
paddingLeft(16f)
143+
}
144+
Text {
145+
attr {
146+
fontSize(14f)
147+
color(Color(0xFF212121L))
148+
text(item.name)
149+
}
150+
}
151+
}
152+
TableCell {
153+
attr {
154+
flex(1f)
155+
justifyContentCenter()
156+
alignItemsCenter()
157+
}
158+
Text {
159+
attr {
160+
fontSize(14f)
161+
color(Color(0xFF212121L))
162+
text(item.score)
163+
}
164+
}
165+
}
166+
TableCell {
167+
attr {
168+
flex(1f)
169+
justifyContentCenter()
170+
alignItemsCenter()
171+
}
172+
View {
173+
attr {
174+
paddingLeft(8f)
175+
paddingRight(8f)
176+
paddingTop(2f)
177+
paddingBottom(2f)
178+
borderRadius(4f)
179+
backgroundColor(gradeColor(item.grade))
180+
}
181+
Text {
182+
attr {
183+
fontSize(12f)
184+
color(Color.WHITE)
185+
text(item.grade)
186+
}
187+
}
188+
}
189+
}
190+
}
191+
}
192+
}
193+
}
194+
}
195+
196+
private fun gradeColor(grade: String): Color = when {
197+
grade.startsWith("A") -> Color(0xFF4CAF50L)
198+
grade.startsWith("B") -> Color(0xFF2196F3L)
199+
grade.startsWith("C") -> Color(0xFFFF9800L)
200+
else -> Color(0xFFF44336L)
201+
}
202+
}

0 commit comments

Comments
 (0)