React-native: Implement allowFontScaling on Android

Created on 16 Jul 2016  路  10Comments  路  Source: facebook/react-native

Android Text components are wanting the ability to disallow font scaling. This is a key feature for design in order to prevent breaking layouts when the user sets their font sizes to huge. Allowing font scaling by default is fine, but there should be a convenient way to disallow it when needed so that apps work well for all users. It is an accessibility concern.

I currently work around this applying the following function in my style sheets:

  // Returns a scale-invariant font size.
  // On iOS this is a no-op, since we can use `allowFontScaling` to disable
  // scaling there. On Android, this reduces the font size so that when Android scales it
  // it will give the desired font size.
  function fixedFont(size) {
    // NOTE: Font Scale should always be the same as the Pixel Ratio on iOS, making this
    // a no-op.
    return size * ReactNative.PixelRatio.get() / ReactNative.PixelRatio.getFontScale();
  }

I have a general idea of how to fix this, but my Java skills chops aren't really up to the task of creating a pull request. The issue seems to be that in ReactTextShadowNode.java:390 we compute the font size from Android's SP units, which scale. What we want, instead, is to do this from DIP units when allowFontScaling is false. This is the recommended way to handle non-scaling font sizes in Android.

So, we would want something like:

if (allowFontScaling) {
  fontSize = (float) Math.ceil(PixelUtil.toPixelFromSP(fontSize));
else {
  fontSize = (float) Math.ceil(PixelUtil.toPixelFromDIP(fontSize));
}
Locked

Most helpful comment

@sibelius if you setText.defaultProps.allowFontScaling = false in index.ios.js, it will set it globally.

All 10 comments

Has there been any progress on this issue?

Running across this issue myself at the moment, @mcrowe would you recommend your approach for the time being?

@awitherow Yes, my approach is annoying: I have probably 300+ calls to fixedFont scattered throughout my code. Still, its the best option right now, AFAIK.

I've replace StyleSheet.create with the following function

export const createStyleSheet = dict => {
    for (let key of Object.keys(dict)) {
        for (let name of Object.keys(dict[key])) {
            if (name === 'fontSize' || name === 'lineHeight') {
                dict[key][name] = fixedFont(dict[key][name])
            }
        }
    }
    return StyleSheet.create(dict)
}

This was fixed by #10898.

@mcrowe is this fixed for u?

@sibelius if you setText.defaultProps.allowFontScaling = false in index.ios.js, it will set it globally.

awesome hack, tks

Yes, I believe this has now been resolved.

For anyone else still struggling with this issue on Android, this did the trick for me:

https://stackoverflow.com/a/32832216/1044620

Was this page helpful?
0 / 5 - 0 ratings

Related issues

oney picture oney  路  3Comments

DreySkee picture DreySkee  路  3Comments

jlongster picture jlongster  路  3Comments

phongyewtong picture phongyewtong  路  3Comments

josev55 picture josev55  路  3Comments