From 1acf33461451834097463f43e70d90bae0f67198 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Aug 2021 21:45:22 -0700 Subject: [PATCH] Fixed `alignItems: baseline` for elements on Android (#31575) Summary: This fixes https://github.com/facebook/react-native/issues/20666 and https://github.com/facebook/react-native/issues/21918. This is pretty much the same as 51b3529f6c2ca354800c0cf6ecb8eb3115eaa36e but implemented for Android. Now exposes the actual base-line offset value that allows Yoga to position it properly when `alignItems: baseline` is requested. ## Changelog [Android][Fixed] - Fixed `alignItems: baseline` for elements on Android Pull Request resolved: https://github.com/facebook/react-native/pull/31575 Test Plan: The same test case that we have for iOS. Before: Screen Shot 2021-05-22 at 7 03 18 PM After: Screen Shot 2021-05-22 at 7 01 51 PM Reviewed By: JoshuaGross Differential Revision: D28631468 Pulled By: yungsters fbshipit-source-id: 7c259e469d19d8344298319f066b8437dfdedad0 --- .../react/views/text/ReactTextShadowNode.java | 16 +++++ .../js/examples/Text/TextExample.android.js | 62 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java index 46bc1e9b500..26257ebe938 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java @@ -32,6 +32,7 @@ import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.UIViewOperationQueue; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.events.RCTEventEmitter; +import com.facebook.yoga.YogaBaselineFunction; import com.facebook.yoga.YogaConstants; import com.facebook.yoga.YogaDirection; import com.facebook.yoga.YogaMeasureFunction; @@ -159,6 +160,20 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode { } }; + private final YogaBaselineFunction mTextBaselineFunction = + new YogaBaselineFunction() { + @Override + public float baseline(YogaNode node, float width, float height) { + Spannable text = + Assertions.assertNotNull( + mPreparedSpannableText, + "Spannable element has not been prepared in onBeforeLayout"); + + Layout layout = measureSpannedText(text, width, YogaMeasureMode.EXACTLY); + return layout.getLineBaseline(layout.getLineCount() - 1); + } + }; + public ReactTextShadowNode() { this(null); } @@ -171,6 +186,7 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode { private void initMeasureFunction() { if (!isVirtual()) { setMeasureFunction(mTextMeasureFunction); + setBaselineFunction(mTextBaselineFunction); } } diff --git a/packages/rn-tester/js/examples/Text/TextExample.android.js b/packages/rn-tester/js/examples/Text/TextExample.android.js index d44aff22b42..aacb5fa973d 100644 --- a/packages/rn-tester/js/examples/Text/TextExample.android.js +++ b/packages/rn-tester/js/examples/Text/TextExample.android.js @@ -884,6 +884,62 @@ const styles = StyleSheet.create({ alignSelf: 'center', }, }); + +function TextBaseLineLayoutExample(props: {}): React.Node { + const texts = []; + for (let i = 9; i >= 0; i--) { + texts.push( + + {i} + , + ); + } + + const marker = ( + + ); + const subtitleStyle = {fontSize: 16, marginTop: 8, fontWeight: 'bold'}; + + return ( + + {'Nested s:'} + + {marker} + {texts} + {marker} + + + {'Array of s in :'} + + {marker} + {texts} + {marker} + + + {'Interleaving and :'} + + {marker} + + Some text. + + {marker} + Text inside View. + {marker} + + + {marker} + + + ); +} + exports.title = 'Text'; exports.documentationURL = 'https://reactnative.dev/docs/text'; exports.category = 'Basic'; @@ -895,4 +951,10 @@ exports.examples = [ return ; }, }, + { + title: "Text `alignItems: 'baseline'` style", + render: function(): React.Node { + return ; + }, + }, ];