在開發App的過程當中咱們會用到各類圖標,經實踐發現一個問題,在React Native中使用圖片來顯示圖標加載會很是慢,常常出現圖標留白,半天才加載出來的狀況。這種時候使用字體圖標就可以很好解決這個問題。與圖片相比,使用字體圖標有哪些好處呢?html
React Native中使用字體圖標最好用的一個庫是react-native-vector-icons,平常開發中這個庫包含的幾個圖標庫基本能知足咱們的需求,若是還有不足的可使用自定義的字體圖標。node
本篇文章主要介紹如下內容,總結和分享開發心得react
react-native-vector-icons
的詳細使用方法。react-native-vector-icons
的高級用法:使用基於iconfont下載的圖標資源建立自定義字體。react-native-vector-icons
的使用首先說說安裝配置:android
npm install react-native-vector-icons --save
或yarn add react-native-vector-icons
安裝。react-native link react-native-vector-icons
命令link這個庫執行react-native link
命令後你會發如今Android目錄下這個庫已經自動爲咱們把字體文件引入到app/src/main
中並建立了assets/fonts
的目錄ios
接着咱們要在android/app/build.gradle
文件中添加如下內容:git
// 自定義的字體文件須要在這裏賦值聲明,若是有多個都須要添加到數組中
project.ext.vectoricons = [
iconFontNames: [ 'iconfont.ttf' ]
]
// 若是隻是使用react-native-vector-icons中的圖標,只添加下面這行就好了,上面那段配置能夠不寫
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
複製代碼
運行react-native link
命令後你會發如今iOS工程目錄下info.plist文件中多了一行Fonts provided by application
,也能夠手動配置,須要把react-native-vector-icons
中全部字體所有加進來,以下:github
Build Phase
中找到
Link Binary With Libraries
,把自動link進來的
libRNVectorIcons.a
這個靜態庫給刪掉,點擊+號按鈕從新添加,這樣iOS端就能編譯成功了。
到這裏,兩邊都已經配置好了,接下來就能夠直接用了。npm
1. 用做Icon組件json
import Icon from 'react-native-vector-icons/FontAwesome';
<Icon name={'angle-right'} size={24} color={'#999'}
複製代碼
下圖是一個設置界面,使用了FontAwesome的圖標react-native
若是同時使用幾個資源庫圖標如FontAwesome、Ionicons、Feather等做爲Icon組件引用,爲了不Icon組件名稱混淆,在import的時候能夠起不一樣的名字,使用的時候組件名對應import的名稱就行。
import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome';
import Icon from 'react-native-vector-icons/Ionicons';
<FontAwesomeIcon name={'angle-right'} size={24} color={'#999'}/>
<Icon name={'ios-sad'} size={100} color={'#999999'}/>
複製代碼
2. 用做Button組件
import Icon from 'react-native-vector-icons/FontAwesome';
<Icon.Button name="star" backgroundColor="#999999" onPress={this.starOnGithub}>
Give me a star on Github😁
</Icon.Button>
複製代碼
3. 用做靜態的圖片資源
有時候咱們可能不想用圖標組件,而想使用Image組件來顯示這些字體圖標,這時怎麼辦呢?看代碼:
import Icon from 'react-native-vector-icons/FontAwesome';
constructor(props) {
super(props);
this.state = {
userIcon: null,
};
}
componentWillMount() {
Icon.getImageSource('user', 50, '#999').then((source) => {
this.setState({
userIcon: source
})
});
}
複製代碼
先在state中聲明一個userIcon,而後使用Icon組件的getImageSource方法獲取圖標資源賦值給userIcon,接着在render函數中須要用到Image組件的地方設置這個userIcon。
<Image source={this.state.userIcon}/>
複製代碼
4. 配合TabBarIOS組件使用
import Icon from 'react-native-vector-icons/Ionicons';
<Icon.TabBarItemIOS
title={'Home'}
iconName={'ios-home-outline'}
selectedIconName={'ios-home'}
iconColor={'#888'}
selectedIconColor={'#ff0098'}
selected={this.state.selectedTabIndex === 0}
renderAsOriginal
onPress={() => {
this.setState({
selectedTabIndex: 0
})
}}
>
複製代碼
5. 在NavigatorIOS組件中使用
NavigatorIOS
是iOS專屬組件,字體圖標在這裏主要是使用在NavigationBar上,使用方式與上面說到的第3點靜態圖片資源的使用是同樣的,這裏很少做贅述。有一點須要注意的是NavigatorIOS
不會隨着state中屬性值改變而從新渲染,因此可能致使getImageSource以後NavigationBar上的圖標不顯示,這裏請看看react-native-vector-icons
的官方文檔,很貼心的說明了避坑指南:
Note: Since NavigatorIOS doesn't rerender with new state and the async nature of getImageSource you must not use it with initialRoute until the icon is rendered, but any view added by push should be fine. Easiest way is to simple add an if statment at the beginning of you render method like this:
render() {
if (!this.state.myIcon) {
return false;
}
return (<NavigatorIOS ... />);
}
複製代碼
簡而言之,就是取值以前加個判斷...
6. 在ToolbarAndroid組件中使用
兩種方式,一種是獲取Icon組件的靜態圖片資源,用在原生的ToolbarAndroid組件中,一種是使用Icon.ToolbarAndroid組件。
import Icon from 'react-native-vector-icons/FontAwesome';
constructor(props) {
super(props);
this.state = {
appLogo: null,
};
}
componentWillMount() {
Icon.getImageSource('android', 36, '#92c029').then((source) => {
this.setState({
appLogo: source
})
});
}
render() {
return (
<View style={styles.container}>
<ToolbarAndroid
style={styles.toolbar_system}
logo={this.state.appLogo}
title={'This is an android toolbar'}
/>
<Icon.ToolbarAndroid
navIconName={'amazon'}
style={styles.toolbar_iconfont}
titleColor="white"
title={'This is an Icon toolbar'}
/>
</View>
)
}
複製代碼
上面說到的都是基於第三方庫的字體圖標的使用方法,若是要使用自定義的圖標,怎麼辦呢?這裏以阿里官方圖標庫來講明。網站須要登陸才能下載資源。
demo_unicode.html
包含了全部圖標對應的unicode字符,咱們就是用它來顯示圖標。
Android放置在app/src/main/assets/fonts
文件夾中,而且在app/src/build.gradle
中添加配置:
project.ext.vectoricons = [
iconFontNames: [ 'iconfont.ttf' ]
]
複製代碼
這裏前面已經說過了。
iOS須要將iconfont.ttf添加到工程裏去,能夠建立一個Fonts文件夾,將iconfont.ttf放入其中,再添加Fonts目錄到工程中。在Info.plist中Fonts provided by application
下添加一行iconfont.ttf。
使用Text組件,設置unicode字符就能夠將圖標顯示出來了。Text組件的fontFamily
要設置爲iconfont
,fontSize
能夠用來設置字體圖標大小。
在實踐中我發現一個問題,單獨使用Text組件給它設置unicode字符就能顯示出圖標,若是有多個圖標我就想偷個懶,把全部unicode字符以字符串的形式放到數組中,用數組的map方法循環顯示Text組件,這時Text組件取值爲字符串,全部圖標都不能正常顯示,所有都是字符串。後來發現這種方式須要把unicode字符串轉換一下,如
轉成\ue6a7
就好了。
這裏不貼代碼了,上圖:
react-native-vector-icons
建立自定義圖標庫直接使用unicode編碼的方式比較簡單,可是在代碼層面來看就不怎麼直觀,畢竟都是unicode編碼,還容易拼寫出錯。使用react-native-vector-icons
建立自定義的圖標庫是更好的選擇,維護起來更加方便,能有效避免出錯。
先看看react-native-vector-icons
中FontAwesome
是怎麼實現建立自定義字體圖標庫的:
import createIconSet from './lib/create-icon-set';
import glyphMap from './glyphmaps/FontAwesome.json';
const iconSet = createIconSet(glyphMap, 'FontAwesome', 'FontAwesome.ttf');
export default iconSet;
export const Button = iconSet.Button;
export const TabBarItem = iconSet.TabBarItem;
export const TabBarItemIOS = iconSet.TabBarItemIOS;
export const ToolbarAndroid = iconSet.ToolbarAndroid;
export const getImageSource = iconSet.getImageSource;
複製代碼
能夠看到使用了react-native-vector-icons
中的createIconSet
方法建立圖標庫,同時根據FontAwesome.json
來匹配圖標。點開發現FontAwesome.json
是圖標名稱和十進制編碼的映射集合:
{
"glass": 61440,
"music": 61441,
"search": 61442,
......
}
複製代碼
咱們如今有了iconfont.ttf,也能夠參照這種方法建立一套字體圖標集合,而後像上面說到的FontAwesome和其它幾個圖標庫的使用方式同樣,來使用咱們的iconfont。
生成iconfont.json
首先是獲取iconfont.json文件,咱們以前下載iconfont資源的時候解壓出來的文件中有個iconfont.svg文件,能夠在其中找到每一個圖標的名字和對應的十六進制unicode編碼,將十六進制編碼轉換成十進制,組成相似上面的FontAwesome.json
同樣的json數據就好了。
But,一個個的來匹配圖標名稱和轉換編碼是繁瑣而笨拙的,這裏咱們使用腳原本完成這個任務。
腳本參考:github.com/zhengcx/RNI…,我使用的是這位大神的腳本。
將iconfont_mapper.sh腳本文件和iconfont.svg放到同一目錄中,打開命令行或終端,執行如下命令:
./iconfont_mapper.sh iconfont.svg
複製代碼
mac下若是報錯Permission denied
就先修改文件權限
chmod 777 iconfont_mapper.sh
複製代碼
而後再執行上述命令,將iconfont.svg轉換獲得一個iconfont.json文件。
建立CustomIconFont
將iconfont.json添加到咱們的項目中,如今就能夠來建立自定義的圖標庫了,建立一個CustomIconFont.js文件,添加如下代碼:
import createIconSet from 'react-native-vector-icons/lib/create-icon-set';
import glyphMap from './iconfont.json';
// glyphMap, fontFamily, fontFile三個參數,注意看react-native-vector-icons官方文檔中方法註釋,
// Android中fontFamily能夠隨便寫,iOS必須是正確的名字不然運行報錯,iOS能夠直接雙擊iconfont.ttf打開看字體實際叫什麼名字
const iconSet = createIconSet(glyphMap, 'iconFont', 'iconfont.ttf');
export default iconSet;
export const Button = iconSet.Button;
export const TabBarItem = iconSet.TabBarItem;
export const TabBarItemIOS = iconSet.TabBarItemIOS;
export const ToolbarAndroid = iconSet.ToolbarAndroid;
export const getImageSource = iconSet.getImageSource;
複製代碼
到這裏相信你們已經知道該怎麼使用這個圖標庫了,沒錯,和react-native-vector-icons
內置的圖標庫使用方法同樣了。
使用示例:
import CustomIconFont from './CustomIconFont';
// 用做圖標組件
<CustomIconFont name={'tubiaozhizuomobanyihuifu_'} size={24} color={'#00c06d'}/>
// 用做Button
<CustomIconFont.Button name={'tubiaozhizuomobanyihuifu_23'} backgroundColor={'#59ACEA'}>
Test icon button
</CustomIconFont.Button>
複製代碼
最後附上一張效果圖:
項目完整代碼地址:github.com/mrarronz/re…, Chapter9-IconfontExample