React Native Environment Info:
System:
OS: macOS High Sierra 10.13.6
CPU: x64 Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
Memory: 184.31 MB / 16.00 GB
Shell: 5.3 - /bin/zsh
Binaries:
Node: 8.11.3 - /usr/local/bin/node
Yarn: 1.9.4 - /usr/local/bin/yarn
npm: 5.6.0 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 11.4, macOS 10.13, tvOS 11.4, watchOS 4.3
Android SDK:
Build Tools: 23.0.1, 26.0.1, 26.0.3, 27.0.3, 28.0.0
API Levels: 23, 25, 26, 27, 28
IDEs:
Android Studio: 3.1 AI-173.4819257
Xcode: 9.4.1/9F2000 - /usr/bin/xcodebuild
npmPackages:
react: 16.4.1 => 16.4.1
react-native: 0.56.0 => 0.56.0
npmGlobalPackages:
react-native-cli: 2.0.1
Since 0.54.x, adjustsFontSizeToFit option in Text has not been working. It worked as expected on 0.53.x
import React, {Component} from 'react';
import {StyleSheet, Text, View} from 'react-native';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.text} allowFontScaling>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#F5FCFF',
},
text: {
fontSize: 30,
color: '#333333',
marginBottom: 5,
},
});
This is still happening in 0.56 and 0.57, adjustsFontSizeToFit works fine on iOS but does nothing on Android
Yep, still happening on 0.57. Is there any workaround?
Extremely hacky and extremely no-no. Full combat solution until I find something better
I created a text component that for Ios basically returns Text and in android returns a Text with this onLayout thing on top of it.
Please I can't encourage anyone enough to not use this in their projects, and find a real solution but if you are in a hurry this patched my problem
<Text
onLayout={(event) => {
if (!this.props.adjustsFontSizeToFit || typeof this.props.children !== 'string') return
let {width} = event.nativeEvent.layout
this.setState({fontSize: Math.floor(1.7 * (width / this.props.children.length))})
}}
{...this.props}
style={[this.props.style, this.state.fontSize && {fontSize: this.state.fontSize}]}
>
{this.props.children}
</Text>)
This is not a fix of course 1.7 is a random number that seems to fit my project properly in all resolutions I have tested so far, onLayout fires after render so there is a bit of a visual glitch etc... etc...
I will try to find a decent fix if it doesn't get fixed eventually but for now, I'm going with this shameful hack.
I can confirm that this is still happening.
@pabloga265 I _think_ the above might work better if you can use Dimensions to determine screen width and calculate the correct fontSize before the first render.
@pabloga265 I took your code and took out the constants. TLDR: you're code breaks for some font-families, mine should fix that. See below.
Basically, I took figured if we have to render the text twice, we might as well get some useful information, so I'm rendering the first pass at fontSize 5 (if we start out too small it gets less accurate because the letters are so small). I did some testing and found the following:
monospace width = length * fontSize * 3 / 5
where length is the number of characters in the text. We can also get the width at fontSize 5:
monospace width at fontSize 5 = length * 5 * 3 / 5 = length * 3
Now, we can calculate how wide our actual text would be in myFontFamily after render by applying the ratio between these two monospace widths to the reported width at fontSize 5 from onLayout:
myFontFamily width = myFontFamily width at 5 (reported width ) * ( monospace width / monospace width at 5)
myFontFamily width = reported width * length * fontSize * 3 / (length * 3 * 5)
myFontFamily width = reported width * fontSize / 5
We can use also use this equation to calculate an appropriate fontSize to get the desired width of the text element.
I was also running into some problems with multiple adjustments so I created a switch that would only allow it to be adjusted one time.
I also made sure to use the smaller of the two fontSize values, as your code adjusts no matter what, while the adjustsFontSizeToFit property only shrinks text that is clipping.
export default class ResponsiveText extends React.Component {
/*
This is an extension of text that handles implements the adjustsFontSizeToFit for android. The bug that it's
patching is documented here:
https://github.com/facebook/react-native/issues/20906
*/
state = {
_style: {
fontSize: 5,
width: null,
},
_adjusted: false
}
onLayout = (event) => {
const { adjustsFontSizeToFit, style, children } = this.props
if (adjustsFontSizeToFit && style.width && typeof children === 'string') {
if (!this.state._adjusted) {
const {width} = event.nativeEvent.layout
this.setState({
_style: {
fontSize: Math.min(style.fontSize, Math.floor(5 * style.width / width)),
width: style.width,
},
_adjusted: true,
})
}
}
else {
this.setState({
_style: {
fontSize: this.props.style.fontSize,
width: this.props.style.width,
},
_adjusted: true,
})
}
}
render() {
return (
Platform.OS === 'ios'
? <Text {...this.props}/>
: <Text onLayout={this.onLayout} {...this.props}
style={[this.props.style, this.state._style]}
/>
)
}
}
If you want to use a value of "numberOfLines" >= 1 you have to modify a little this component, because how it's written it will always calculate a fontSize that will fit in just 1 line. I needed a numberOfLines = 2.
changing
const { adjustsFontSizeToFit, style, children } = this.props
in
const { adjustsFontSizeToFit, style, children,numberOfLines } = this.props
and
fontSize: Math.min(style.fontSize, Math.floor(5 * style.width / width))
in
fontSize: Math.min(style.fontSize, Math.floor(5 * style.width / width * numberOfLines))
did the trick for me.
Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.
Most helpful comment
@pabloga265 I took your code and took out the constants. TLDR: you're code breaks for some font-families, mine should fix that. See below.
Basically, I took figured if we have to render the text twice, we might as well get some useful information, so I'm rendering the first pass at fontSize 5 (if we start out too small it gets less accurate because the letters are so small). I did some testing and found the following:
monospace width = length * fontSize * 3 / 5where
lengthis the number of characters in the text. We can also get the width at fontSize 5:monospace width at fontSize 5 = length * 5 * 3 / 5 = length * 3Now, we can calculate how wide our actual text would be in
myFontFamilyafter render by applying the ratio between these two monospace widths to the reported width at fontSize 5 from onLayout:We can use also use this equation to calculate an appropriate fontSize to get the desired width of the text element.
I was also running into some problems with multiple adjustments so I created a switch that would only allow it to be adjusted one time.
I also made sure to use the smaller of the two fontSize values, as your code adjusts no matter what, while the adjustsFontSizeToFit property only shrinks text that is clipping.