Skip to content

Commit 7e00154

Browse files
committed
fix(android): track vertical gravity in DrawCommandSpan draw offset
The DrawCommandSpan draw block in `ReactTextView.onDraw` translated by `getCompoundPaddingLeft(), getExtendedPaddingTop()` only, which works for the default `Gravity.TOP` text alignment. When `textAlignVertical` is `center` or `bottom` and the text is shorter than the view, the glyphs are positioned by `super.onDraw` with an additional gravity offset that the span draws were missing — so colored underline/strikethrough rendered at the top of the view while the text itself was vertically centered or bottom-aligned. Recompute the offset locally (mirroring TextView.getVerticalOffset(), which is private upstream) and add it to the translate before invoking the span draws. ## Changelog [ANDROID] [FIXED] - Custom text decorations track `textAlignVertical` ## Test Plan Render a `<Text style={{ height: 200, textAlignVertical: 'center', textDecorationLine: 'underline', textDecorationColor: '#ff00aa', fontSize: 24 }}>Hello</Text>` inside a fixed-height parent and verify the magenta underline sits flush under "Hello" in the vertical center. Repeat with `textAlignVertical: 'bottom'`. Both now track the text; previously the underline stayed at the top of the box. Verified on Android API 36 emulator.
1 parent 8f291a3 commit 7e00154

1 file changed

Lines changed: 18 additions & 1 deletion

File tree

  • packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,25 @@ protected void onDraw(Canvas canvas) {
221221
DrawCommandSpan[] drawSpans =
222222
spanned.getSpans(0, spanned.length(), DrawCommandSpan.class);
223223
if (drawSpans.length > 0) {
224+
// Mirror TextView.getVerticalOffset() — it's private upstream so we
225+
// recompute the gravity-driven offset that `super.onDraw` applies
226+
// before painting glyphs. Without this the span draws would land at
227+
// the top of the view while text is centered or bottom-aligned.
228+
int voffsetText = 0;
229+
if ((getGravity() & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
230+
int boxHeight =
231+
getMeasuredHeight() - getExtendedPaddingTop() - getExtendedPaddingBottom();
232+
int textHeight = layout.getHeight();
233+
if (textHeight < boxHeight) {
234+
int v = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
235+
voffsetText =
236+
(v == Gravity.BOTTOM)
237+
? (boxHeight - textHeight)
238+
: (boxHeight - textHeight) / 2;
239+
}
240+
}
224241
canvas.save();
225-
canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());
242+
canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop() + voffsetText);
226243
for (DrawCommandSpan span : drawSpans) {
227244
int start = spanned.getSpanStart(span);
228245
int end = spanned.getSpanEnd(span);

0 commit comments

Comments
 (0)