Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 25.2k
Android Text: More robust logic for handling inherited text props#22917
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,143 @@ | ||
| /** | ||
| * Copyright (c) Facebook, Inc. and its affiliates. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
| /* | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we move this to the top of the java class? | ||
| * Currently, TextAttributes consists of a subset of text props that need to be passed from parent | ||
| * to child so inheritance can be implemented correctly. An example complexity that causes a prop | ||
| * to end up in TextAttributes is when multiple props need to be considered together to determine | ||
| * the rendered aka effective value. For example, to figure out the rendered/effective font size, | ||
| * you need to take into account the fontSize and allowFontScaling props. | ||
| */ | ||
| package com.facebook.react.views.text; | ||
| import com.facebook.react.uimanager.PixelUtil; | ||
| import com.facebook.react.uimanager.ViewDefaults; | ||
| public class TextAttributes { | ||
| private boolean mAllowFontScaling = true; | ||
| private float mFontSize = Float.NaN; | ||
| private float mLineHeight = Float.NaN; | ||
| private float mLetterSpacing = Float.NaN; | ||
| private float mHeightOfTallestInlineImage = Float.NaN; | ||
| public TextAttributes() { | ||
| } | ||
| public TextAttributes applyChild(TextAttributes child) { | ||
| TextAttributes result = new TextAttributes(); | ||
| // allowFontScaling is always determined by the root Text | ||
| // component so don't allow the child to overwrite it. | ||
| result.mAllowFontScaling = mAllowFontScaling; | ||
| result.mFontSize = !Float.isNaN(child.mFontSize) ? child.mFontSize : mFontSize; | ||
| result.mLineHeight = !Float.isNaN(child.mLineHeight) ? child.mLineHeight : mLineHeight; | ||
| result.mLetterSpacing = !Float.isNaN(child.mLetterSpacing) ? child.mLetterSpacing : mLetterSpacing; | ||
| result.mHeightOfTallestInlineImage = !Float.isNaN(child.mHeightOfTallestInlineImage) ? child.mHeightOfTallestInlineImage : mHeightOfTallestInlineImage; | ||
| return result; | ||
| } | ||
| // Getters and setters | ||
| // | ||
| public boolean getAllowFontScaling() { | ||
| return mAllowFontScaling; | ||
| } | ||
| public void setAllowFontScaling(boolean value) { | ||
| mAllowFontScaling = value; | ||
| } | ||
| public float getFontSize() { | ||
| return mFontSize; | ||
| } | ||
| public void setFontSize(float value) { | ||
| mFontSize = value; | ||
| } | ||
| public float getLineHeight() { | ||
| return mLineHeight; | ||
| } | ||
| public void setLineHeight(float value) { | ||
| mLineHeight = value; | ||
| } | ||
| public float getLetterSpacing() { | ||
| return mLetterSpacing; | ||
| } | ||
| public void setLetterSpacing(float value) { | ||
| mLetterSpacing = value; | ||
| } | ||
| public float getHeightOfTallestInlineImage() { | ||
| return mHeightOfTallestInlineImage; | ||
| } | ||
| public void setHeightOfTallestInlineImage(float value) { | ||
| mHeightOfTallestInlineImage = value; | ||
| } | ||
| // Getters for effective values | ||
| // | ||
| // In general, these return `Float.NaN` if the property doesn't have a value. | ||
| // | ||
| // Always returns a value because uses a hardcoded default as a fallback. | ||
| public int getEffectiveFontSize() { | ||
| float fontSize = !Float.isNaN(mFontSize) ? mFontSize : ViewDefaults.FONT_SIZE_SP; | ||
| return mAllowFontScaling | ||
| ? (int) Math.ceil(PixelUtil.toPixelFromSP(fontSize)) | ||
| : (int) Math.ceil(PixelUtil.toPixelFromDIP(fontSize)); | ||
| } | ||
| public float getEffectiveLineHeight() { | ||
| if (Float.isNaN(mLineHeight)) { | ||
| return Float.NaN; | ||
| } | ||
| float lineHeight = mAllowFontScaling | ||
| ? PixelUtil.toPixelFromSP(mLineHeight) | ||
| : PixelUtil.toPixelFromDIP(mLineHeight); | ||
| // Take into account the requested line height | ||
| // and the height of the inline images. | ||
| boolean useInlineViewHeight = | ||
| !Float.isNaN(mHeightOfTallestInlineImage) | ||
| && mHeightOfTallestInlineImage > lineHeight; | ||
| return useInlineViewHeight ? mHeightOfTallestInlineImage : lineHeight; | ||
| } | ||
| public float getEffectiveLetterSpacing() { | ||
| if (Float.isNaN(mLetterSpacing)) { | ||
| return Float.NaN; | ||
| } | ||
| return mAllowFontScaling | ||
| ? PixelUtil.toPixelFromSP(mLetterSpacing) | ||
| : PixelUtil.toPixelFromDIP(mLetterSpacing); | ||
| } | ||
| public String toString() { | ||
| return ( | ||
| "TextAttributes {" | ||
| + "\n getAllowFontScaling(): " + getAllowFontScaling() | ||
| + "\n getFontSize(): " + getFontSize() | ||
| + "\n getEffectiveFontSize(): " + getEffectiveFontSize() | ||
| + "\n getHeightOfTallestInlineImage(): " + getHeightOfTallestInlineImage() | ||
| + "\n getLetterSpacing(): " + getLetterSpacing() | ||
| + "\n getEffectiveLetterSpacing(): " + getEffectiveLetterSpacing() | ||
| + "\n getLineHeight(): " + getLineHeight() | ||
| + "\n getEffectiveLineHeight(): " + getEffectiveLineHeight() | ||
| + "\n}" | ||
| ); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably we can simplify logic if
parentTextAttributesalways be non-null. So we can implementTextAttributes::defaultTextAttributes()(with default values, obviously) and pass into the function initially.I am not sure about this though. I am also curious how I did this in Fabric.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I had a
defaultTextAttributes(), I could get rid of theparentTextAttributes == nullchecks.Some tricky things to watch out for:
floatnow andfloathasFloat.NaN)?fontSizeto the span even if it matches the default value (ViewDefaults.FONT_SIZE_SP).