ReactNative乾貨分享——自定義iconfont圖標的使用

在開發App的過程當中咱們會用到各類圖標,經實踐發現一個問題,在React Native中使用圖片來顯示圖標加載會很是慢,常常出現圖標留白,半天才加載出來的狀況。這種時候使用字體圖標就可以很好解決這個問題。與圖片相比,使用字體圖標有哪些好處呢?html

字體圖標的優勢

  1. 基於Text組件來顯示,加載速度快
  2. 能夠設置字體樣式來改變圖標的大小,顏色
  3. 矢量圖標,放大縮小不失真
  4. 兼容性好,適用於各式瀏覽器
  5. 設計簡單,圖標庫豐富,如FontAwesomeiconfont
  6. 最重要的一點,不會像圖片那樣因爲一點小小的改動就換來換去,咱們直接修改字體樣式就好了✌️

React Native中使用字體圖標最好用的一個庫是react-native-vector-icons,平常開發中這個庫包含的幾個圖標庫基本能知足咱們的需求,若是還有不足的可使用自定義的字體圖標。node

本篇文章主要介紹如下內容,總結和分享開發心得react

  1. react-native-vector-icons的詳細使用方法。
  2. 從阿里官方圖標庫iconfont下載字體圖標的使用方法,不使用其它第三方庫。
  3. react-native-vector-icons的高級用法:使用基於iconfont下載的圖標資源建立自定義字體。

react-native-vector-icons的使用

首先說說安裝配置:android

安裝和配置

  1. 根目錄下使用npm install react-native-vector-icons --saveyarn add react-native-vector-icons安裝。
  2. 安裝完成後運行react-native link react-native-vector-icons命令link這個庫
  3. Android端的配置

執行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"
複製代碼
  1. iOS端的配置

運行react-native link命令後你會發如今iOS工程目錄下info.plist文件中多了一行Fonts provided by application,也能夠手動配置,須要把react-native-vector-icons中全部字體所有加進來,以下:github

接着在Xcode的 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>
    )
  }
複製代碼

阿里矢量圖標庫iconfont的使用

上面說到的都是基於第三方庫的字體圖標的使用方法,若是要使用自定義的圖標,怎麼辦呢?這裏以阿里官方圖標庫來講明。網站須要登陸才能下載資源。

  1. iconfont隨便選擇一組圖標,將全部圖標加入到購物車中,點擊購物車,點擊下方下載代碼將資源下載到本地。
  2. 解壓zip文件,能夠看到文件夾中有如下文件:

其中 demo_unicode.html包含了全部圖標對應的unicode字符,咱們就是用它來顯示圖標。

  1. 將iconfont.ttf文件分別copy到Android和iOS工程目錄下。

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要設置爲iconfontfontSize能夠用來設置字體圖標大小。

在實踐中我發現一個問題,單獨使用Text組件給它設置unicode字符就能顯示出圖標,若是有多個圖標我就想偷個懶,把全部unicode字符以字符串的形式放到數組中,用數組的map方法循環顯示Text組件,這時Text組件取值爲字符串,全部圖標都不能正常顯示,所有都是字符串。後來發現這種方式須要把unicode字符串轉換一下,如&#xe6a7;轉成\ue6a7就好了。

這裏不貼代碼了,上圖:

使用react-native-vector-icons建立自定義圖標庫

直接使用unicode編碼的方式比較簡單,可是在代碼層面來看就不怎麼直觀,畢竟都是unicode編碼,還容易拼寫出錯。使用react-native-vector-icons建立自定義的圖標庫是更好的選擇,維護起來更加方便,能有效避免出錯。

先看看react-native-vector-iconsFontAwesome是怎麼實現建立自定義字體圖標庫的:

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

相關文章
相關標籤/搜索