Skip to content

Commit 282063e

Browse files
joevilchesfacebook-github-bot
authored andcommitted
Use PreparedLayout as opposed to Layout in PreparedLayoutTextView (facebook#51711)
Summary: Pull Request resolved: facebook#51711 This is needed to support textVerticalAlign as we are storing that offset in the prepared layout and need to read it from the new text view Changelog: [Internal] Reviewed By: NickGerleman Differential Revision: D75643360
1 parent 031aa4f commit 282063e

File tree

3 files changed

+35
-34
lines changed

3 files changed

+35
-34
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/PreparedLayoutTextView.kt

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,20 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
4141
private var clickableSpans: List<ClickableSpan> = emptyList()
4242
private var selection: TextSelection? = null
4343

44-
public var layout: Layout? = null
44+
public var preparedLayout: PreparedLayout? = null
4545
set(value) {
4646
if (field != value) {
4747
val lastSelection = selection
4848
if (lastSelection != null) {
49-
if (value != null && field?.text.toString() == value.text.toString()) {
50-
value.getSelectionPath(lastSelection.start, lastSelection.end, lastSelection.path)
49+
if (value != null && field?.layout?.text.toString() == value.layout.text.toString()) {
50+
value.layout.getSelectionPath(
51+
lastSelection.start, lastSelection.end, lastSelection.path)
5152
} else {
5253
clearSelection()
5354
}
5455
}
5556

56-
clickableSpans = value?.text?.let { filterClickableSpans(it) } ?: emptyList()
57+
clickableSpans = value?.layout?.text?.let { filterClickableSpans(it) } ?: emptyList()
5758

5859
field = value
5960
invalidate()
@@ -73,7 +74,7 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
7374
public @ColorInt var selectionColor: Int? = null
7475

7576
public val text: CharSequence?
76-
get() = layout?.text
77+
get() = preparedLayout?.layout?.text
7778

7879
init {
7980
initView()
@@ -84,7 +85,7 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
8485
private fun initView() {
8586
clickableSpans = emptyList()
8687
selection = null
87-
layout = null
88+
preparedLayout = null
8889
}
8990

9091
public fun recycleView(): Unit {
@@ -101,17 +102,17 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
101102
super.onDraw(canvas)
102103
canvas.translate(paddingLeft.toFloat(), paddingTop.toFloat())
103104

104-
val textLayout = layout
105-
if (textLayout != null) {
105+
val layout = preparedLayout?.layout
106+
if (layout != null) {
106107
if (selection != null) {
107108
selectionPaint.setColor(
108109
selectionColor ?: DefaultStyleValuesUtil.getDefaultTextColorHighlight(context))
109110
}
110111

111112
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
112-
Api34Utils.draw(textLayout, canvas, selection?.path, selectionPaint)
113+
Api34Utils.draw(layout, canvas, selection?.path, selectionPaint)
113114
} else {
114-
textLayout.draw(canvas, selection?.path, selectionPaint, 0)
115+
layout.draw(canvas, selection?.path, selectionPaint, 0)
115116
}
116117
}
117118
}
@@ -121,21 +122,21 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
121122
}
122123

123124
public fun setSelection(start: Int, end: Int) {
124-
val textLayout = checkNotNull(layout)
125-
if (start < 0 || end > textLayout.text.length || start >= end) {
125+
val layout = checkNotNull(preparedLayout).layout
126+
if (start < 0 || end > layout.text.length || start >= end) {
126127
throw IllegalArgumentException(
127-
"setSelection start and end are not in valid range. start: $start, end: $end, text length: ${textLayout.text.length}")
128+
"setSelection start and end are not in valid range. start: $start, end: $end, text length: ${layout.text.length}")
128129
}
129130

130131
val textSelection = selection
131132
if (textSelection == null) {
132133
val selectionPath = Path()
133-
textLayout.getSelectionPath(start, end, selectionPath)
134+
layout.getSelectionPath(start, end, selectionPath)
134135
selection = TextSelection(start, end, selectionPath)
135136
} else {
136137
textSelection.start = start
137138
textSelection.end = end
138-
textLayout.getSelectionPath(start, end, textSelection.path)
139+
layout.getSelectionPath(start, end, textSelection.path)
139140
}
140141

141142
invalidate()
@@ -171,9 +172,9 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
171172
clearSelection()
172173
clickableSpan.onClick(this)
173174
} else if (action == MotionEvent.ACTION_DOWN) {
174-
val textLayout = checkNotNull(layout)
175-
val start = (textLayout.text as Spanned).getSpanStart(clickableSpan)
176-
val end = (textLayout.text as Spanned).getSpanEnd(clickableSpan)
175+
val layout = checkNotNull(preparedLayout).layout
176+
val start = (layout.text as Spanned).getSpanStart(clickableSpan)
177+
val end = (layout.text as Spanned).getSpanEnd(clickableSpan)
177178
setSelection(start, end)
178179
}
179180

@@ -205,19 +206,19 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
205206
}
206207

207208
private fun getTextOffsetAt(x: Int, y: Int): Int {
208-
val textLayout = layout ?: return -1
209-
val line = textLayout.getLineForVertical(y)
209+
val layout = preparedLayout?.layout ?: return -1
210+
val line = layout.getLineForVertical(y)
210211

211212
val left: Float
212213
val right: Float
213214

214-
if (textLayout.alignment == Layout.Alignment.ALIGN_CENTER) {
215+
if (layout.alignment == Layout.Alignment.ALIGN_CENTER) {
215216
/**
216217
* [Layout#getLineLeft] and [Layout#getLineRight] properly account for paragraph margins on
217218
* centered text.
218219
*/
219-
left = textLayout.getLineLeft(line)
220-
right = textLayout.getLineRight(line)
220+
left = layout.getLineLeft(line)
221+
right = layout.getLineRight(line)
221222
} else {
222223
/**
223224
* [Layout#getLineLeft] and [Layout#getLineRight] do NOT properly account for paragraph
@@ -229,19 +230,19 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
229230
* [Layout#getLineMax] gives the extent *plus* the leading margin, so we can figure out the
230231
* rest from there.
231232
*/
232-
val rtl = textLayout.getParagraphDirection(line) == Layout.DIR_RIGHT_TO_LEFT
233+
val rtl = layout.getParagraphDirection(line) == Layout.DIR_RIGHT_TO_LEFT
233234
left =
234-
if (rtl) (textLayout.width - textLayout.getLineMax(line))
235-
else textLayout.getParagraphLeft(line).toFloat()
236-
right = if (rtl) textLayout.getParagraphRight(line).toFloat() else textLayout.getLineMax(line)
235+
if (rtl) (layout.width - layout.getLineMax(line))
236+
else layout.getParagraphLeft(line).toFloat()
237+
right = if (rtl) layout.getParagraphRight(line).toFloat() else layout.getLineMax(line)
237238
}
238239

239240
if (x < left || x > right) {
240241
return -1
241242
}
242243

243244
return try {
244-
textLayout.getOffsetForHorizontal(line, x.toFloat())
245+
layout.getOffsetForHorizontal(line, x.toFloat())
245246
} catch (e: ArrayIndexOutOfBoundsException) {
246247
// This happens for bidi text on Android 7-8.
247248
// See

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/PreparedLayoutTextViewManager.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@ internal class PreparedLayoutTextViewManager :
6262

6363
override fun updateExtraData(view: PreparedLayoutTextView, extraData: Any) {
6464
SystraceSection("PreparedLayoutTextViewManager.updateExtraData").use { _ ->
65-
val layout = (extraData as PreparedLayout).layout
66-
view.layout = layout
65+
val preparedLayout = extraData as PreparedLayout
66+
view.preparedLayout = preparedLayout
6767

6868
// If this text view contains any clickable spans, set a view tag and reset the accessibility
6969
// delegate so that these can be picked up by the accessibility system.
70-
if (layout.text is Spanned) {
71-
val spannedText = layout.text as Spanned
70+
if (preparedLayout.layout.text is Spanned) {
71+
val spannedText = preparedLayout.layout.text as Spanned
7272
val accessibilityLinks = AccessibilityLinks(spannedText)
7373
view.setTag(
7474
R.id.accessibility_links,

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewAccessibilityDelegate.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ internal class ReactTextViewAccessibilityDelegate : ReactAccessibilityDelegate {
149149

150150
private fun getLayoutFromHost(): Layout? {
151151
return if (hostView is PreparedLayoutTextView) {
152-
(hostView as PreparedLayoutTextView).layout
152+
(hostView as PreparedLayoutTextView).preparedLayout?.layout
153153
} else if (hostView is TextView) {
154154
(hostView as TextView).layout
155155
} else {
@@ -166,7 +166,7 @@ internal class ReactTextViewAccessibilityDelegate : ReactAccessibilityDelegate {
166166
private fun getSpannedFromHost(): Spanned? {
167167
val host = hostView
168168
return if (host is PreparedLayoutTextView) {
169-
host.layout?.text as? Spanned
169+
host.preparedLayout?.layout?.text as? Spanned
170170
} else if (host is TextView) {
171171
host.text as? Spanned
172172
} else {

0 commit comments

Comments
 (0)