@@ -40,6 +40,7 @@ import splitties.views.dsl.core.withTheme
40
40
import splitties.views.dsl.core.wrapContent
41
41
import splitties.views.horizontalPadding
42
42
import splitties.views.verticalPadding
43
+ import kotlin.math.roundToInt
43
44
44
45
@SuppressLint(" ViewConstructor" )
45
46
class CandidatesView (
@@ -59,11 +60,20 @@ class CandidatesView(
59
60
60
61
private var shouldUpdatePosition = false
61
62
63
+ /* *
64
+ * layout update may or may not cause [CandidatesView]'s size [onSizeChanged],
65
+ * in either case, we should reposition it
66
+ */
62
67
private val layoutListener =
63
68
OnGlobalLayoutListener {
64
69
shouldUpdatePosition = true
65
70
}
66
71
72
+ /* *
73
+ * [CandidatesView]'s position is calculated based on it's size,
74
+ * so we need to recalculate the position after layout,
75
+ * and before any actual drawing to avoid flicker
76
+ */
67
77
private val preDrawListener =
68
78
OnPreDrawListener {
69
79
if (shouldUpdatePosition) {
@@ -103,33 +113,37 @@ class CandidatesView(
103
113
menu.candidates.isNotEmpty()
104
114
105
115
private fun updateUi () {
116
+ preeditUi.update(inputComposition)
117
+ preeditUi.root.visibility = if (preeditUi.visible) View .VISIBLE else View .INVISIBLE
118
+ // if CandidatesView can be shown, rime engine is ready most of the time,
119
+ // so it should be safety to get option immediately
120
+ val isHorizontalLayout = rime.run { getRuntimeOption(" _horizontal" ) }
121
+ candidatesUi.update(menu, isHorizontalLayout)
106
122
if (evaluateVisibility()) {
107
- preeditUi.update(inputComposition)
108
- preeditUi.root.visibility = if (preeditUi.visible) View .VISIBLE else View .INVISIBLE
109
- // if CandidatesView can be shown, rime engine is ready most of the time,
110
- // so it should be safety to get option immediately
111
- val isHorizontalLayout = rime.run { getRuntimeOption(" _horizontal" ) }
112
- candidatesUi.update(menu, isHorizontalLayout)
113
123
visibility = View .VISIBLE
114
124
} else {
125
+ // RecyclerView won't update its items when ancestor view is GONE
126
+ visibility = View .INVISIBLE
115
127
touchEventReceiverWindow.dismiss()
116
- visibility = GONE
117
128
}
118
129
}
119
130
120
131
private fun updatePosition () {
121
- val x: Float
122
- val y: Float
123
- val (horizontal, top, _, bottom) = anchorPosition
132
+ if (visibility != View .VISIBLE ) return
124
133
val (parentWidth, parentHeight) = parentSize
125
134
if (parentWidth <= 0 || parentHeight <= 0 ) {
126
135
translationX = 0f
127
136
translationY = 0f
128
137
return
129
138
}
130
- val selfWidth = width.toFloat()
131
- val selfHeight = height.toFloat()
139
+ val (horizontal, top, _, bottom) = anchorPosition
140
+ val w = width
141
+ val h = height
142
+ val selfWidth = w.toFloat()
143
+ val selfHeight = h.toFloat()
132
144
145
+ val x: Float
146
+ val y: Float
133
147
val minX = 0f
134
148
val minY = 0f
135
149
val maxX = parentWidth - selfWidth
@@ -165,9 +179,7 @@ class CandidatesView(
165
179
translationX = x
166
180
translationY = y
167
181
// update touchEventReceiverWindow's position after CandidatesView's
168
- if (evaluateVisibility()) {
169
- touchEventReceiverWindow.showup()
170
- }
182
+ touchEventReceiverWindow.showAt(x.roundToInt(), y.roundToInt(), w, h)
171
183
shouldUpdatePosition = false
172
184
}
173
185
@@ -183,7 +195,7 @@ class CandidatesView(
183
195
}
184
196
185
197
init {
186
- visibility = View .GONE
198
+ visibility = View .INVISIBLE
187
199
188
200
minWidth = dp(theme.generalStyle.layout.minWidth)
189
201
minHeight = dp(theme.generalStyle.layout.minHeight)
0 commit comments