1
+ package com.icuxika.bittersweet.demo.controller
2
+
3
+ import com.icuxika.bittersweet.demo.annotation.AppFXML
4
+ import com.icuxika.bittersweet.dsl.onAction
5
+ import javafx.beans.property.SimpleDoubleProperty
6
+ import javafx.beans.property.SimpleObjectProperty
7
+ import javafx.beans.property.SimpleStringProperty
8
+ import javafx.collections.FXCollections
9
+ import javafx.collections.ObservableList
10
+ import javafx.fxml.FXML
11
+ import javafx.fxml.Initializable
12
+ import javafx.geometry.Insets
13
+ import javafx.scene.control.Button
14
+ import javafx.scene.control.Label
15
+ import javafx.scene.control.ListCell
16
+ import javafx.scene.control.ListView
17
+ import javafx.scene.image.Image
18
+ import javafx.scene.image.ImageView
19
+ import javafx.scene.layout.*
20
+ import javafx.scene.paint.Color
21
+ import javafx.scene.shape.SVGPath
22
+ import javafx.scene.text.Font
23
+ import javafx.scene.text.TextFlow
24
+ import javafx.util.Callback
25
+ import java.net.URL
26
+ import java.util.*
27
+
28
+ @AppFXML(fxml = " fxml/chat-view.fxml" )
29
+ class ChatViewController : Initializable {
30
+
31
+ @FXML
32
+ private lateinit var rootContainer: StackPane
33
+
34
+ @FXML
35
+ private lateinit var container: BorderPane
36
+
37
+ private val messageObservableList: ObservableList <Message > = FXCollections .observableArrayList()
38
+
39
+ override fun initialize (location : URL ? , resources : ResourceBundle ? ) {
40
+ container.top = Button (" 测试" ).apply {
41
+ onAction {
42
+ messageObservableList.filter { it.type == 2 }[0 ].imageUrl =
43
+ " https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
44
+ (container.center as ListView <* >).refresh()
45
+ }
46
+ }
47
+ container.center = ListView <Message >().apply {
48
+ styleClass.add(" message-list-view" )
49
+ items = messageObservableList
50
+ cellFactory = Callback <ListView <Message >, ListCell <Message >> {
51
+ object : ListCell <Message >() {
52
+ val leftMsgDecorateTextFlow by lazy {
53
+ createTextFlow(
54
+ " M-0,0c0,565.161 458.839,1024 1024,1024l-0,-716.8c-408.482,0 -785.067,-137.652 -1024,-307.2Z"
55
+ )
56
+ }
57
+ val rightMsgDecorateTextFlow by lazy {
58
+ createTextFlow(
59
+ " M0,307.2l0,716.8c565.161,0 1024,-458.839 1024,-1024c-238.933,169.548 -615.518,307.2 -1024,307.2Z"
60
+ )
61
+ }
62
+
63
+ val textProperty = SimpleStringProperty ()
64
+ val leftTextNode by lazy {
65
+ val text = createText()
66
+ AnchorPane ().apply {
67
+ AnchorPane .setLeftAnchor(text, 24.0 )
68
+ AnchorPane .setTopAnchor(text, 0.0 )
69
+ AnchorPane .setLeftAnchor(leftMsgDecorateTextFlow, 4.0 )
70
+ AnchorPane .setTopAnchor(leftMsgDecorateTextFlow, 2.0 )
71
+ children.addAll(text, leftMsgDecorateTextFlow)
72
+ }
73
+ }
74
+ val rightTextNode by lazy {
75
+ val text = createText()
76
+ AnchorPane ().apply {
77
+ AnchorPane .setRightAnchor(text, 24.0 )
78
+ AnchorPane .setTopAnchor(text, 0.0 )
79
+ AnchorPane .setRightAnchor(rightMsgDecorateTextFlow, 4.0 )
80
+ AnchorPane .setTopAnchor(rightMsgDecorateTextFlow, 2.0 )
81
+ children.addAll(text, rightMsgDecorateTextFlow)
82
+ }
83
+ }
84
+
85
+ fun createText (): TextFlow = TextFlow ().apply {
86
+ padding = Insets (8.0 )
87
+ background = Background (BackgroundFill (Color .DODGERBLUE , CornerRadii (16.0 ), Insets .EMPTY ))
88
+ children.add(Label ().apply {
89
+ textProperty().bind(textProperty)
90
+ textFill = Color .WHITE
91
+ font = Font .font(16.0 )
92
+ maxWidth = 240.0
93
+ isWrapText = true
94
+ })
95
+ }
96
+
97
+ val imageProperty = SimpleObjectProperty <Image >()
98
+ val fitWidthProperty = SimpleDoubleProperty ()
99
+ val leftImageNode by lazy {
100
+ val image = createImage()
101
+ AnchorPane ().apply {
102
+ AnchorPane .setLeftAnchor(image, 24.0 )
103
+ AnchorPane .setTopAnchor(image, 0.0 )
104
+ AnchorPane .setLeftAnchor(leftMsgDecorateTextFlow, 4.0 )
105
+ AnchorPane .setTopAnchor(leftMsgDecorateTextFlow, 2.0 )
106
+ children.addAll(image, leftMsgDecorateTextFlow)
107
+ }
108
+ }
109
+ val rightImageNode by lazy {
110
+ val image = createImage()
111
+ AnchorPane ().apply {
112
+ AnchorPane .setRightAnchor(image, 24.0 )
113
+ AnchorPane .setTopAnchor(image, 0.0 )
114
+ AnchorPane .setRightAnchor(rightMsgDecorateTextFlow, 4.0 )
115
+ AnchorPane .setTopAnchor(rightMsgDecorateTextFlow, 2.0 )
116
+ children.addAll(image, rightMsgDecorateTextFlow)
117
+ }
118
+ }
119
+
120
+ fun createImage (): TextFlow = TextFlow ().apply {
121
+ padding = Insets (8.0 )
122
+ background = Background (BackgroundFill (Color .DODGERBLUE , CornerRadii (16.0 ), Insets .EMPTY ))
123
+ val imageView = ImageView ().apply {
124
+ imageProperty().bind(imageProperty)
125
+ fitWidthProperty().bind(fitWidthProperty)
126
+ isPreserveRatio = true
127
+ isCache = true
128
+ }
129
+ children.add(imageView)
130
+ }
131
+
132
+ override fun updateItem (item : Message ? , empty : Boolean ) {
133
+ super .updateItem(item, empty)
134
+
135
+ if (empty || item == null ) {
136
+ text = null
137
+ graphic = null
138
+ } else {
139
+ text = null
140
+ graphic = when (item.type) {
141
+ 1 -> {
142
+ textProperty.bind(item.msgProperty())
143
+ if (item.left) {
144
+ leftTextNode
145
+ } else {
146
+ rightTextNode
147
+ }
148
+ }
149
+
150
+ 2 -> {
151
+ if (imageProperty.get() == null || imageProperty.get().url != item.imageUrl) {
152
+ imageProperty.set(Image (item.imageUrl, true ).apply {
153
+ progressProperty().addListener { observable, oldValue, newValue ->
154
+ if (newValue == 1.0 ) {
155
+ println (imageProperty.get().width)
156
+ if (imageProperty.get().width > 240.0 ) {
157
+ fitWidthProperty.set(240.0 )
158
+ }
159
+ }
160
+ }
161
+ })
162
+ }
163
+ if (item.left) {
164
+ leftImageNode
165
+ } else {
166
+ rightImageNode
167
+ }
168
+ }
169
+
170
+ else -> throw IllegalArgumentException ()
171
+ }
172
+ }
173
+ }
174
+ }
175
+ }
176
+ }
177
+
178
+ messageObservableList.addAll(
179
+ Message ().apply {
180
+ left = true
181
+ setMsg(" 你要好好长大,不要输给风,不要输给雨,不要输给冬雪,不要输给炎夏。少年人,你在孩童时应当快乐,使你的心欢畅,行你所愿行的,见你所愿见的,然而也应当记住黑暗的时日。但愿新的梦想永远不被无留陀侵蚀,但愿旧的故事与无留陀一同被忘却,但愿绿色的原野,山丘永远不会变得枯黄,但愿溪水永远清澈,但愿鲜花永远盛开。挚友将再次同行于茂密的森林中,一切美好的事物终将归来,一切痛苦的记忆也会远去,就像溪水净化自己,枯树绽出新芽。最终,森林会记住一切。" )
182
+ },
183
+ Message ().apply {
184
+ left = false
185
+ setMsg(" 如此绚丽的花朵,不该在绽放之前就枯萎。我会赠予你璀璨的祝福,而你的灵魂,也将绽放更耀眼的光辉。亲爱的山雀,请将我的箭,我的花,与我的爱,带给那孑然独行的旅人。愿你前行的道路有群星闪耀。愿你留下的足迹有百花绽放。你即是上帝的馈赠,世界因你而瑰丽。" )
186
+ },
187
+ Message ().apply {
188
+ left = true
189
+ type = 2
190
+ },
191
+ Message ().apply {
192
+ left = true
193
+ type = 2
194
+ imageUrl = " https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg"
195
+ },
196
+ Message ().apply {
197
+ left = true
198
+ setMsg(" 你要好好长大,不要输给风,不要输给雨,不要输给冬雪,不要输给炎夏。少年人,你在孩童时应当快乐,使你的心欢畅,行你所愿行的,见你所愿见的,然而也应当记住黑暗的时日。但愿新的梦想永远不被无留陀侵蚀,但愿旧的故事与无留陀一同被忘却,但愿绿色的原野,山丘永远不会变得枯黄,但愿溪水永远清澈,但愿鲜花永远盛开。挚友将再次同行于茂密的森林中,一切美好的事物终将归来,一切痛苦的记忆也会远去,就像溪水净化自己,枯树绽出新芽。最终,森林会记住一切。" )
199
+ },
200
+ Message ().apply {
201
+ left = false
202
+ setMsg(" 如此绚丽的花朵,不该在绽放之前就枯萎。我会赠予你璀璨的祝福,而你的灵魂,也将绽放更耀眼的光辉。亲爱的山雀,请将我的箭,我的花,与我的爱,带给那孑然独行的旅人。愿你前行的道路有群星闪耀。愿你留下的足迹有百花绽放。你即是上帝的馈赠,世界因你而瑰丽。" )
203
+ },
204
+ Message ().apply {
205
+ left = true
206
+ type = 2
207
+ imageUrl = " https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg"
208
+ },
209
+ Message ().apply {
210
+ left = true
211
+ setMsg(" 你要好好长大,不要输给风,不要输给雨,不要输给冬雪,不要输给炎夏。少年人,你在孩童时应当快乐,使你的心欢畅,行你所愿行的,见你所愿见的,然而也应当记住黑暗的时日。但愿新的梦想永远不被无留陀侵蚀,但愿旧的故事与无留陀一同被忘却,但愿绿色的原野,山丘永远不会变得枯黄,但愿溪水永远清澈,但愿鲜花永远盛开。挚友将再次同行于茂密的森林中,一切美好的事物终将归来,一切痛苦的记忆也会远去,就像溪水净化自己,枯树绽出新芽。最终,森林会记住一切。" )
212
+ },
213
+ Message ().apply {
214
+ left = true
215
+ setMsg(" 你要好好长大,不要输给风,不要输给雨,不要输给冬雪,不要输给炎夏。少年人,你在孩童时应当快乐,使你的心欢畅,行你所愿行的,见你所愿见的,然而也应当记住黑暗的时日。但愿新的梦想永远不被无留陀侵蚀,但愿旧的故事与无留陀一同被忘却,但愿绿色的原野,山丘永远不会变得枯黄,但愿溪水永远清澈,但愿鲜花永远盛开。挚友将再次同行于茂密的森林中,一切美好的事物终将归来,一切痛苦的记忆也会远去,就像溪水净化自己,枯树绽出新芽。最终,森林会记住一切。" )
216
+ },
217
+ Message ().apply {
218
+ left = true
219
+ setMsg(" 你要好好长大,不要输给风,不要输给雨,不要输给冬雪,不要输给炎夏。少年人,你在孩童时应当快乐,使你的心欢畅,行你所愿行的,见你所愿见的,然而也应当记住黑暗的时日。但愿新的梦想永远不被无留陀侵蚀,但愿旧的故事与无留陀一同被忘却,但愿绿色的原野,山丘永远不会变得枯黄,但愿溪水永远清澈,但愿鲜花永远盛开。挚友将再次同行于茂密的森林中,一切美好的事物终将归来,一切痛苦的记忆也会远去,就像溪水净化自己,枯树绽出新芽。最终,森林会记住一切。" )
220
+ },
221
+ Message ().apply {
222
+ left = false
223
+ setMsg(" 如此绚丽的花朵,不该在绽放之前就枯萎。我会赠予你璀璨的祝福,而你的灵魂,也将绽放更耀眼的光辉。亲爱的山雀,请将我的箭,我的花,与我的爱,带给那孑然独行的旅人。愿你前行的道路有群星闪耀。愿你留下的足迹有百花绽放。你即是上帝的馈赠,世界因你而瑰丽。" )
224
+ },
225
+ )
226
+ }
227
+
228
+ private fun createTextFlow (svgContent : String , size : Double = 24.0): TextFlow = TextFlow ().apply {
229
+ shape = SVGPath ().apply {
230
+ content = svgContent
231
+ }
232
+ background = Background (BackgroundFill (Color .DODGERBLUE , CornerRadii .EMPTY , Insets .EMPTY ))
233
+ minWidth = size
234
+ minHeight = size
235
+ maxWidth = size
236
+ maxHeight = size
237
+ }
238
+
239
+ class Message {
240
+ var left: Boolean = true
241
+
242
+ var type: Int = 1
243
+
244
+ private val msg = SimpleStringProperty ()
245
+ fun msgProperty () = msg
246
+ fun setMsg (value : String ) {
247
+ msg.set(value)
248
+ }
249
+
250
+ fun getMsg () = msg.get()
251
+
252
+ var imageUrl = " https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg"
253
+ }
254
+ }
0 commit comments