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

相关文章
相关标签/搜索