ReactNative字體大小不隨系統(tǒng)字體大小變化而變化

引言

在開發(fā)react-nativeApp時,相信大家都應該遇到過這樣的問題:用戶設置了系統(tǒng)的字體大小之后,導致自己的APP布局紊亂,甚至有些內(nèi)容會被切掉/隱藏,這對于用戶來講,是非常不好的用戶體驗。

那為什么會出現(xiàn)這種情況呢呢?原因是我們在開發(fā)的時候,布局的前提是系統(tǒng)的字體大小設置為默認大小,所以只能保證在系統(tǒng)字體大小正常的情況下,我們的布局是友好的,

那么,我們應該如何解決這個問題呢?今天這篇文章,就給大家介紹幾種解決方案。

Text和TextInput

react-native中用來顯示文字的,一般會用到兩個組件:TextTextInput。所以,我們只要針對這兩個組件做好工作,那就基本上解決了字體大小適配的問題

TextTextInput它們有一個共同屬性:

allowFontScaling

這個屬性在react-native官方文檔中解釋如下:

Specifies whether fonts should scale to respect Text Size accessibility settings. The default is true.

意思是:

是否隨系統(tǒng)指定的文字大小變化而變化。默認值為true

這給我提供了解決方案,只要我們給TextTextInput的屬性allowFontScaling設置值為false,那么文字大小就不會隨系統(tǒng)字體大小的變化而變化。

設置allowFontScaling

我們有幾種方式來設置TextTextInputallowFontScaling。第一種:

1. 給TextTextInput組件設置allowFontScaling = false

<Text allowFontScaling={false}/>
<TextInput allowFontScaling={false}/> 

這種方案效率很低,需要在每個使用到這兩個組件的地方都加上這個屬性。但是一般這兩個組件的使用率還是很高的,所以這是一個龐大的工作量,而且在開發(fā)過程當中,我們也很容易忘記設置它

那么有沒有更好實現(xiàn)方式呢?當然有,這就是下面講的第二種:

2. 自定義MyText/MyTextInput組件

我們可以自定義一個組件MyText, 然后統(tǒng)一設置allowFontScaling = false屬性,然后在其他需要調(diào)用的時候,直接用MyText代替Text

MyText.js

import React from 'react'
import {Text} from 'react-native'

export default class MyText extends React.Component {

    render() {
        return (
            <Text
                allowFontScaling={false}
                {...this.props}>
                {this.props.children}
            </Text>
        )
    }
}

這個方案足夠好了,但是,你仍然可能在某段代碼里,忘記使用MyText而是直接使用Text,這個時候,問題依然會出現(xiàn)。

那么,就沒有一種萬無一失的方案嗎?當然有啦,第三種:

3. 重寫Text的render()

是的,我們可以重寫Textrender()方法,讓Text在渲染的時候,設置allowFontScaling = false。這里,我們需要用到lodashwrap()方法:

0.56(不包括)版本之前

Text.prototype.render = _.wrap(Text.prototype.render, function (func, ...args) {
    let originText = func.apply(this, args)
    return React.cloneElement(originText, {allowFontScaling: false})
})

注意1:
react-native版本0.56之前,Text是通過React的createReactClass方式來創(chuàng)建類的,也就是說,是通過javascriptprototype的方式來創(chuàng)建類。所以重寫render方法時,需要通過Text.prototype.render來引用

而在0.56版本,Text改為了es6extends的實現(xiàn)方式來創(chuàng)建類,所以,需要如下方式來重寫render

0.56(包括)版本之后

Text.render = _.wrap(Text.render, function (func, ...args) {
    let originText = func.apply(this, args)
    return React.cloneElement(originText, {allowFontScaling: false})
})

大家可以查看源碼,或者查看0.56change-log

注意2:
這段代碼最好放在你app整個組件執(zhí)行調(diào)用之前,比如在我的項目中,我放的位置:

import React from 'react'
import {AppRegistry, Text, DeviceEventEmitter, YellowBox} from 'react-native'
import {Provider} from 'react-redux'
import App from './src/App'
import _ from 'lodash'


//字體不隨系統(tǒng)字體變化
Text.render = _.wrap(Text.render, function (func, ...args) {
    let originText = func.apply(this, args)
    return React.cloneElement(originText, {allowFontScaling: false})
})

...
...

class MyApp extends React.Component {
    render() {
        return (
            <Provider store={store}>
                <App/>
            </Provider>
        )
    }
}

AppRegistry.registerComponent("xxx", () => MyApp);

注意3:
但是很遺憾的是,這個只適用于Text,TextInput不能用于此方案。

那么,有沒有一種方案,能夠同時兼容TextTextInput并且做到一勞永逸呢?當然有了,終極方案:

4. 完美方案:修改defaultProps

首先我們來看各種組件的源碼.

TextInput.js

...
  getDefaultProps(): Object {
    return {
      allowFontScaling: true,
      underlineColorAndroid: 'transparent',
    };
  },
...

Text.js

...
  static defaultProps = {
    accessible: true,
    allowFontScaling: true,
    ellipsizeMode: 'tail',
  };
...

通過這兩個代碼片段可以知道,在定義TextTextInput時,都有給組件設置默認屬性的操作.

所以我們可以:

TextInput.defaultProps = Object.assign({}, TextInput.defaultProps, {defaultProps: false})
Text.defaultProps = Object.assign({}, Text.defaultProps, {allowFontScaling: false})

來直接設置TextTextInputallowFontScaling屬性默認值為false,真正實現(xiàn)了一勞永逸。

確保react-navigation兼容

通過設置defaultProps的方式來修改allowFontScaling的值為false,會有一個問題。

大家在使用react-native時,最常用到的navigator應該是react-navigation。你需要單獨設置headertitleallowfontscalingallowFontScaling來確保react-navigationtabTitleheaderTitle沒有問題。

結語

好了,到此,我們就完美解決了react-native開發(fā)中,字體大小不隨系統(tǒng)字體大小變化而變化的問題。

我們總結一下:

  1. react-native中使用TextTextInput負責顯示文字信息
  2. TextTextInput中設置allowFontScaling=false可以讓字體大小不隨系統(tǒng)設置而變化
  3. 可以通過單個組件設置、自定義組件、重寫render()、設置defaultProps默認值這四種方式來設置allowFontScaling的值為false
  4. 對于重寫render()、設置defaultProps默認值這兩種方式,需要把設置代碼放在app組件初始化之前。
  5. 確保react-navigation兼容
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容