在開發react-native
App時,相信你們都應該遇到過這樣的問題:用戶設置了系統的字體大小以後,致使本身的APP佈局紊亂,甚至有些內容會被切掉/隱藏,這對於用戶來說,是很是很差的用戶體驗。javascript
那爲何會出現這種狀況呢呢?緣由是咱們在開發的時候,佈局的前提是系統的字體大小設置爲默認大小,因此只能保證在系統字體大小正常的狀況下,咱們的佈局是友好的,html
那麼,咱們應該如何解決這個問題呢?今天這篇文章,就給你們介紹幾種解決方案。java
在react-native
中用來顯示文字的,通常會用到兩個組件:Text
和TextInput
。因此,咱們只要針對這兩個組件作好工做,那就基本上解決了字體大小適配的問題react
Text
和TextInput
它們有一個共同屬性:ios
allowFontScaling
git
這個屬性在react-native
官方文檔中解釋以下:es6
Specifies whether fonts should scale to respect Text Size accessibility settings. The default is
true
.github
意思是:redux
是否隨系統指定的文字大小變化而變化。默認值爲
true
react-native
這給我提供瞭解決方案,只要咱們給Text
和TextInput
的屬性allowFontScaling
設置值爲false
,那麼文字大小就不會隨系統字體大小的變化而變化。
咱們有幾種方式來設置Text
和TextInput
的allowFontScaling
。第一種:
Text
和TextInput
組件設置allowFontScaling = false
<Text allowFontScaling={false}/>
<TextInput allowFontScaling={false}/>
複製代碼
這種方案效率很低,須要在每一個使用到這兩個組件的地方都加上這個屬性。可是通常這兩個組件的使用率仍是很高的,因此這是一個龐大的工做量,並且在開發過程中,咱們也很容易忘記設置它
那麼有沒有更好實現方式呢?固然有,這就是下面講的第二種:
咱們能夠自定義一個組件MyText
, 而後統一設置allowFontScaling = false
屬性,而後在其餘須要調用的時候,直接用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
,這個時候,問題依然會出現。
那麼,就沒有一種萬無一失的方案嗎?固然有啦,第三種:
是的,咱們能夠重寫Text
的render()
方法,讓Text
在渲染的時候,設置allowFontScaling = false
。這裏,咱們須要用到lodash
的wrap()
方法:
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
方式來建立類的,也就是說,是經過javascript
的prototype
的方式來建立類。因此重寫render
方法時,須要經過Text.prototype.render
來引用
而在0.56
版本,Text
改成了es6
中extends
的實現方式來建立類,因此,須要以下方式來重寫render
:
0.56(包括)版本以後
Text.render = _.wrap(Text.render, function (func, ...args) {
let originText = func.apply(this, args)
return React.cloneElement(originText, {allowFontScaling: false})
})
複製代碼
你們能夠查看源碼,或者查看0.56
的change-log
注意2: 這段代碼最好放在你app整個組件執行調用以前,好比在個人項目中,我放的位置:
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'
//字體不隨系統字體變化
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
不能用於此方案。
那麼,有沒有一種方案,可以同時兼容Text
和TextInput
而且作到一勞永逸呢?固然有了,終極方案:
首先咱們來看各類組件的源碼.
...
getDefaultProps(): Object {
return {
allowFontScaling: true,
underlineColorAndroid: 'transparent',
};
},
...
複製代碼
...
static defaultProps = {
accessible: true,
allowFontScaling: true,
ellipsizeMode: 'tail',
};
...
複製代碼
經過這兩個代碼片斷能夠知道,在定義Text
和TextInput
時,都有給組件設置默認屬性的操做.
因此咱們能夠:
TextInput.defaultProps = Object.assign({}, TextInput.defaultProps, {defaultProps: false})
Text.defaultProps = Object.assign({}, Text.defaultProps, {allowFontScaling: false})
複製代碼
來直接設置Text
和TextInput
的allowFontScaling
屬性默認值爲false
,真正實現了一勞永逸。
經過設置defaultProps
的方式來修改allowFontScaling
的值爲false
,會有一個問題。
你們在使用react-native
時,最經常使用到的navigator
應該是react-navigation。你須要單獨設置headertitleallowfontscaling和allowFontScaling來確保react-navigation的tabTitle
和headerTitle
沒有問題。
好了,到此,咱們就完美解決了 react-native
開發中,字體大小不隨系統字體大小變化而變化 的問題。
咱們總結一下:
react-native
中使用Text
和TextInput
負責顯示文字信息Text
和TextInput
中設置allowFontScaling=false
可讓字體大小不隨系統設置而變化render()
、設置defaultProps
默認值這四種方式來設置allowFontScaling
的值爲false
render()
、設置defaultProps
默認值這兩種方式,須要把設置代碼放在app組件初始化以前。react-navigation
兼容