From 86b0e7fd56bcfcd38af1cdb4a5d5d24c63d41e52 Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Thu, 12 Jan 2023 09:47:51 +0100 Subject: [PATCH] Implement logic that uses TextView height to align text without lineHeight. Reimplement solution from commit and comment (also relevant comment-1, commit-1, comment-2 and commit-2) which uses total height and number of lines to calculate average height. If textAttributes.mFontSize is not null, use the average lineHeight to position the text. --- .../react/views/text/CustomStyleSpan.java | 33 ++++++++++++------- .../views/text/ReactTextViewManager.java | 24 ++++++++++---- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java index b5bff398cc56e7..dd9206d15786f1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java @@ -38,6 +38,8 @@ public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan { private final String mCurrentText; private String mTextAlignVertical; private int mHighestLineHeight; + private int mLineHeight; + private int mLineCount; public CustomStyleSpan( int fontStyle, @@ -67,7 +69,8 @@ public void updateDrawState(TextPaint ds) { mAssetManager, mTextAlignVertical, mCurrentText, - mHighestLineHeight); + mHighestLineHeight, + mLineHeight); } @Override @@ -81,7 +84,8 @@ public void updateMeasureState(TextPaint paint) { mAssetManager, mTextAlignVertical, mCurrentText, - mHighestLineHeight); + mHighestLineHeight, + mLineHeight); } public int getStyle() { @@ -105,7 +109,8 @@ private static void apply( AssetManager assetManager, @Nullable String textAlignVertical, String currentText, - int highestLineHeight) { + int highestLineHeight, + int lineHeight) { Typeface typeface = ReactTypefaceUtils.applyStyles(paint.getTypeface(), style, weight, family, assetManager); paint.setFontFeatureSettings(fontFeatureSettings); @@ -119,33 +124,39 @@ private static void apply( if (highestLineHeight != 0) { // the span with the highest lineHeight sets the height for all rows paint.baselineShift -= highestLineHeight / 2 - paint.getTextSize() / 2; + } else if (lineHeight > 0) { + paint.baselineShift -= lineHeight / 2 - paint.getTextSize() / 2; } else { // works only with single line and without fontSize // https://bit.ly/3W2eJKT // if lineHeight is not set, align the text using the font metrics // https://stackoverflow.com/a/27631737/7295772 - // top ------------- -26 - // ascent ------------- -30 - // baseline __my Text____ 0 - // descent _____________ 8 - // bottom _____________ 1 - paint.baselineShift += paint.getFontMetrics().top - paint.getFontMetrics().ascent; + // top ------------- + // ascent ------------- + // baseline __my Text____ + // descent _____________ + // bottom _____________ + // paint.baselineShift += paint.getFontMetrics().top - paint.getFontMetrics().ascent; } } if (textAlignVertical == "bottom-child") { if (highestLineHeight != 0) { // the span with the highest lineHeight sets the height for all rows paint.baselineShift += highestLineHeight / 2 - paint.getTextSize() / 2; + } else if (lineHeight > 0) { + paint.baselineShift += lineHeight / 2 - paint.getTextSize() / 2; } else { // works only with single line and without fontSize // https://bit.ly/3W2eJKT - paint.baselineShift += paint.getFontMetrics().bottom - paint.descent(); + // paint.baselineShift += paint.getFontMetrics().bottom - paint.descent(); } } } } - public void updateSpan(int highestLineHeight) { + public void updateSpan(int highestLineHeight, int lineCount, int lineHeight) { mHighestLineHeight = highestLineHeight; + mLineCount = lineCount; + mLineHeight = lineHeight; } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java index 07b47e0ace36f6..e7f60c942a1924 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java @@ -8,9 +8,11 @@ package com.facebook.react.views.text; import android.content.Context; +import android.text.Layout; import android.text.Spannable; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.facebook.common.logging.FLog; import com.facebook.react.R; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableNativeMap; @@ -43,6 +45,7 @@ public class ReactTextViewManager private static final short TX_STATE_KEY_MOST_RECENT_EVENT_COUNT = 3; @VisibleForTesting public static final String REACT_CLASS = "RCTText"; + private static final String TAG = "ReactTextViewManager"; protected @Nullable ReactTextViewManagerCallback mReactTextViewManagerCallback; @@ -104,20 +107,27 @@ public void updateExtraData(ReactTextView view, Object extraData) { CustomLineHeightSpan[] customLineHeightSpans = spannable.getSpans(0, spannable.length(), CustomLineHeightSpan.class); + int highestLineHeight = 0; if (customLineHeightSpans.length > 0) { - int highestLineHeight = 0; for (CustomLineHeightSpan span : customLineHeightSpans) { if (highestLineHeight == 0 || span.getLineHeight() > highestLineHeight) { highestLineHeight = span.getLineHeight(); } } + } - CustomStyleSpan[] customStyleSpans = - spannable.getSpans(0, spannable.length(), CustomStyleSpan.class); - if (customStyleSpans.length != 0) { - for (CustomStyleSpan span : customStyleSpans) { - span.updateSpan(highestLineHeight); - } + CustomStyleSpan[] customStyleSpans = + spannable.getSpans(0, spannable.length(), CustomStyleSpan.class); + if (customStyleSpans.length != 0) { + Layout layout = view.getLayout(); + int lineCount = layout != null ? layout.getLineCount() : 1; + int lineHeight = layout != null ? layout.getHeight() : 0; + String methodName = new Object() {}.getClass().getEnclosingMethod().getName(); + FLog.w( + "React::" + TAG, + methodName + " update.getText(): " + (update.getText()) + " lineHeight: " + (lineHeight)); + for (CustomStyleSpan span : customStyleSpans) { + span.updateSpan(highestLineHeight, lineCount, lineHeight); } } }