Skip to content

Commit

Permalink
iOS: Add a maxFontSizeMultiplier prop to <Text> and <TextInput> (face…
Browse files Browse the repository at this point in the history
…book#20915)

Summary:
**Motivation**

Whenever a user changes the system font size to its maximum allowable setting, React Native apps that allow font scaling can become unusable because the text gets too big. Experimenting with a native app like iMessage on iOS, the font size used for non-body text (e.g. header, navigational elements) is capped while the body text (e.g. text in the message bubbles) is allowed to grow.

This PR introduces a new prop on `<Text>` and `<TextInput>` called `maxFontSizeMultiplier`. This enables devs to set the maximum allowed text scale factor on a Text/TextInput. The default is 0 which means no limit.

Another PR will add this feature to Android.

**Test Plan**

I created a test app which utilizes all categories of values of `maxFontSizeMultiplier`:
  - `undefined`: inherit from parent
  - `0`: no limit
  - `1`, `1.2`: fixed limits

I tried this with `Text`, `TextInput` with `value`, and `TextInput` with children. For `Text`, I also verified that nesting works properly (if a child `Text` doesn't specify `maxFontSizeMultiplier`, it inherits it from its parent).

Lastly, we've been using a version of this in Skype for several months.

**Release Notes**

[GENERAL] [ENHANCEMENT] [Text/TextInput] - Added maxFontSizeMultiplier prop to prevent some text from getting unusably large as user increases OS's font scale setting (iOS)

Adam Comella
Microsoft Corp.
Pull Request resolved: facebook#20915

Differential Revision: D9646739

Pulled By: shergin

fbshipit-source-id: c823f59c1e342c22d6297b88b2cb11c5a1f10310
  • Loading branch information
Adam Comella authored and gengjiawen committed Sep 14, 2018
1 parent a16c1dc commit e2b0e69
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 4 deletions.
15 changes: 14 additions & 1 deletion Libraries/Components/TextInput/TextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ type Props = $ReadOnly<{|
autoCorrect?: ?boolean,
autoFocus?: ?boolean,
allowFontScaling?: ?boolean,
maxFontSizeMultiplier?: ?boolean,
editable?: ?boolean,
keyboardType?: ?KeyboardType,
returnKeyType?: ?ReturnKeyType,
Expand Down Expand Up @@ -367,6 +368,14 @@ const TextInput = createReactClass({
* default is `true`.
*/
allowFontScaling: PropTypes.bool,
/**
* Specifies largest possible scale a font can reach when `allowFontScaling` is enabled.
* Possible values:
* `null/undefined` (default): inherit from the parent node or the global default (0)
* `0`: no max, ignore parent/global default
* `>= 1`: sets the maxFontSizeMultiplier of this node to this value
*/
maxFontSizeMultiplier: PropTypes.number,
/**
* If `false`, text is not editable. The default value is `true`.
*/
Expand Down Expand Up @@ -933,7 +942,11 @@ const TextInput = createReactClass({
);
if (childCount >= 1) {
children = (
<Text style={props.style} allowFontScaling={props.allowFontScaling}>
<Text
style={props.style}
allowFontScaling={props.allowFontScaling}
maxFontSizeMultiplier={props.maxFontSizeMultiplier}
>
{children}
</Text>
);
Expand Down
1 change: 1 addition & 0 deletions Libraries/Text/BaseText/RCTBaseTextViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ - (RCTShadowView *)shadowView
RCT_REMAP_SHADOW_PROPERTY(fontStyle, textAttributes.fontStyle, NSString)
RCT_REMAP_SHADOW_PROPERTY(fontVariant, textAttributes.fontVariant, NSArray)
RCT_REMAP_SHADOW_PROPERTY(allowFontScaling, textAttributes.allowFontScaling, BOOL)
RCT_REMAP_SHADOW_PROPERTY(maxFontSizeMultiplier, textAttributes.maxFontSizeMultiplier, CGFloat)
RCT_REMAP_SHADOW_PROPERTY(letterSpacing, textAttributes.letterSpacing, CGFloat)
// Paragraph Styles
RCT_REMAP_SHADOW_PROPERTY(lineHeight, textAttributes.lineHeight, CGFloat)
Expand Down
3 changes: 2 additions & 1 deletion Libraries/Text/RCTTextAttributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ extern NSString *const RCTTextAttributesTagAttributeName;
@property (nonatomic, copy, nullable) NSString *fontFamily;
@property (nonatomic, assign) CGFloat fontSize;
@property (nonatomic, assign) CGFloat fontSizeMultiplier;
@property (nonatomic, assign) CGFloat maxFontSizeMultiplier;
@property (nonatomic, copy, nullable) NSString *fontWeight;
@property (nonatomic, copy, nullable) NSString *fontStyle;
@property (nonatomic, copy, nullable) NSArray<NSString *> *fontVariant;
Expand Down Expand Up @@ -71,7 +72,7 @@ extern NSString *const RCTTextAttributesTagAttributeName;
- (UIFont *)effectiveFont;

/**
* Font size multiplier reflects `allowFontScaling` and `fontSizeMultiplier`.
* Font size multiplier reflects `allowFontScaling`, `fontSizeMultiplier`, and `maxFontSizeMultiplier`.
*/
- (CGFloat)effectiveFontSizeMultiplier;

Expand Down
13 changes: 12 additions & 1 deletion Libraries/Text/RCTTextAttributes.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ - (instancetype)init
_lineHeight = NAN;
_textDecorationStyle = NSUnderlineStyleSingle;
_fontSizeMultiplier = NAN;
_maxFontSizeMultiplier = NAN;
_alignment = NSTextAlignmentNatural;
_baseWritingDirection = NSWritingDirectionNatural;
_textShadowRadius = NAN;
Expand All @@ -49,6 +50,7 @@ - (void)applyTextAttributes:(RCTTextAttributes *)textAttributes
_fontFamily = textAttributes->_fontFamily ?: _fontFamily;
_fontSize = !isnan(textAttributes->_fontSize) ? textAttributes->_fontSize : _fontSize;
_fontSizeMultiplier = !isnan(textAttributes->_fontSizeMultiplier) ? textAttributes->_fontSizeMultiplier : _fontSizeMultiplier;
_maxFontSizeMultiplier = !isnan(textAttributes->_maxFontSizeMultiplier) ? textAttributes->_maxFontSizeMultiplier : _maxFontSizeMultiplier;
_fontWeight = textAttributes->_fontWeight ?: _fontWeight;
_fontStyle = textAttributes->_fontStyle ?: _fontStyle;
_fontVariant = textAttributes->_fontVariant ?: _fontVariant;
Expand Down Expand Up @@ -191,7 +193,15 @@ - (UIFont *)effectiveFont

- (CGFloat)effectiveFontSizeMultiplier
{
return !RCTHasFontHandlerSet() && _allowFontScaling && !isnan(_fontSizeMultiplier) ? _fontSizeMultiplier : 1.0;
bool fontScalingEnabled = !RCTHasFontHandlerSet() && _allowFontScaling;

if (fontScalingEnabled) {
CGFloat fontSizeMultiplier = !isnan(_fontSizeMultiplier) ? _fontSizeMultiplier : 1.0;
CGFloat maxFontSizeMultiplier = !isnan(_maxFontSizeMultiplier) ? _maxFontSizeMultiplier : 0.0;
return maxFontSizeMultiplier >= 1.0 ? fminf(maxFontSizeMultiplier, fontSizeMultiplier) : fontSizeMultiplier;
} else {
return 1.0;
}
}

- (UIColor *)effectiveForegroundColor
Expand Down Expand Up @@ -260,6 +270,7 @@ - (BOOL)isEqual:(RCTTextAttributes *)textAttributes
RCTTextAttributesCompareObjects(_fontFamily) &&
RCTTextAttributesCompareFloats(_fontSize) &&
RCTTextAttributesCompareFloats(_fontSizeMultiplier) &&
RCTTextAttributesCompareFloats(_maxFontSizeMultiplier) &&
RCTTextAttributesCompareStrings(_fontWeight) &&
RCTTextAttributesCompareObjects(_fontStyle) &&
RCTTextAttributesCompareObjects(_fontVariant) &&
Expand Down
2 changes: 2 additions & 0 deletions Libraries/Text/Text.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const viewConfig = {
numberOfLines: true,
ellipsizeMode: true,
allowFontScaling: true,
maxFontSizeMultiplier: true,
disabled: true,
selectable: true,
selectionColor: true,
Expand Down Expand Up @@ -263,6 +264,7 @@ const RCTVirtualText =
validAttributes: {
...ReactNativeViewAttributes.UIView,
isHighlighted: true,
maxFontSizeMultiplier: true,
},
uiViewClassName: 'RCTVirtualText',
}));
Expand Down
1 change: 0 additions & 1 deletion Libraries/Text/Text/RCTTextViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ @interface RCTTextViewManager () <RCTUIManagerObserver>
@implementation RCTTextViewManager
{
NSHashTable<RCTTextShadowView *> *_shadowViews;
CGFloat _fontSizeMultiplier;
}

RCT_EXPORT_MODULE(RCTText)
Expand Down
8 changes: 8 additions & 0 deletions Libraries/Text/TextPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ module.exports = {
* See https://facebook.github.io/react-native/docs/text.html#allowfontscaling
*/
allowFontScaling: PropTypes.bool,
/**
* Specifies largest possible scale a font can reach when `allowFontScaling` is enabled.
* Possible values:
* `null/undefined` (default): inherit from the parent node or the global default (0)
* `0`: no max, ignore parent/global default
* `>= 1`: sets the maxFontSizeMultiplier of this node to this value
*/
maxFontSizeMultiplier: PropTypes.number,
/**
* Indicates whether the view is an accessibility element.
*
Expand Down

0 comments on commit e2b0e69

Please sign in to comment.