• react-native icon解决方案(svg)


    ** 在开发app的过程中总是少不了各种各样的icon图标。移动端和pc端的解决方式各有不同,而RN与之前的开发方式都有所不同,所以我们要对各种引入图标的方式进行权衡。**

    一: 三种方式

    目前主流的解决图标的方式又三种,如下:
    1.图片
    使用png图片,应该是移动端最普适的方案,对RN来说,使用图片解决图标最简单,也最复杂,简单的是RN自己就能够解析图片,因此不用引入任何外部库,复杂的就是为了ios和安卓的各种屏幕,我们可能要对每个图片准备各种尺寸。
    2. IconFont
    对于web开发来说,字体图标绝对是解决icon最熟悉的方案了。也由此,react-native的开源库react-native-vector-icons开始流行起来。这种方案解决简单,只用引进这个库和.ttf文件,就能像写web一样使用字体图标了。并且现在很多demo都是用字体图标来解决的。
    3.svg
    之所以要把svg和图片分开,就是因为RN是默认不支持svg的,我们需要引入react-native-svg这个库才能渲染svg图标。svg对比图片拥有体积小,而且因其可缩放特性,不用理会用户屏幕的尺寸。

    二:对比

    类型优势劣势
    图片(打包) 使用方便,直接用require和Image标签就可以使用 bundle体积增大,特别是热更新对流量,影响太大。需要根据屏幕不同准备多种尺寸。
    图片(URI) 同上,更换方便,远程管理 基本同上,缓存管理比较麻烦,需要另外的库。
    IconFont 随app打包,文件小,使用便利,不用担心屏幕屏幕尺寸 不能热更新,需要引入额外的库
    svg(打包) 文件极小,可随bundle热更新,可缩放图形,不用担心屏幕尺寸问题 需要引入额外的库
    svg(URI) 基本同图片,不用担心屏幕尺寸 缓存

    三:决定实施方案 (svg)

    鉴于使用图片为了防止模糊,要准备多倍图,首先就被pass掉了。而字体图标做为我常用的手段,特别是公司的字体是通过icomoo这种网站统一管理的,本来是很倾向于使用的,奈何.ttf文件必须随项目打包到app里面,不能热更新。至少在没有放弃codepush的情况下,只能放弃了。接下来就只有使用svg了 。

    svg的体积极小,几十个图标文件加起来不到3k,随bundle打包是最好的选择,正好现在的字体图标管理网站也能生成svg文件,很方便和设计师合作。设计师只用将需要使用的svg图标上传到icomoo上命名好,然后打包下载就能使用。

    使用react-native-svg就能对svg的标签解析成图片,而使用react-native-svg-uri则能把svg文件的xml解析成响应的component。这样就能把svg文件转化成图形。但是后来发现这在安卓中行不通,因为安卓的RN项目在release打包后(非debug模式),只能允许require pngxml格式的文件。不过这并不是什么大问题,本来对icomoo生成svg文件中,我们仅仅需要path标签,其余的都是浪费空间的,而且频繁require静态文件也会减慢速度。我们可以用脚本来将svg文件批量生成js使用的字符串,然后通过react-native-svg-uri来解析xml。这个库作者也考虑到android的问题预留了接受字符串的api。

     
     

    于是我们的使用方式变成了:svg文件->js的xml数据集合->Svg Component。
    另外在react-native-svg-uri更新太慢,其npm包依赖了低版本的react-native-svg。如果你使用的5.0版本以上的svg,会由于原生和react-native-svg-uri所使用的react-native-svg版本不同而报错。其实这个库原理很简单,而且只有两百行代码,很好维护。建议不通过npm直接在项目中使用,可以解决版本问题。

    四:具体步骤

    步骤1: 下载svg文件


     
    icomoo仓库

    以我使用的icomoo为例,打包下载下来的SVG文件夹如下


     
    QQ20170324-190940@2x.png

    步骤2:脚本处理
    每次进app请求多个svg很浪费资源,并且安卓本身就不支持svg静态文件的require,所以我们需要用简单的脚本处理一下,把多个svg的字符合并到一个js对象中,代码如下,运行下面的脚本 node getSvg。这里我时用node写的,当然你也可以用自己习惯的脚本语言来处理。

    //  getSvg.js
    var fs = require('fs');
    var path = require('path');
    const svgDir = path.resolve(__dirname, './svgs');
    
    // 读取单个文件
    function readfile(filename) {
      return new Promise((resolve, reject) => {
        fs.readFile(path.join(svgDir, filename), 'utf8', function(err, data) {
          console.log(data.replace(/<?xml.*??>|<!--.*?-->|<!DOCTYPE.*?>/g, ''));
          if (err) reject(err);
          resolve({
            [filename.slice(0, filename.lastIndexOf('.'))]: data,
          });
        });
      });
    }
    
    // 读取SVG文件夹下所有svg
    function readSvgs() {
      return new Promise((resolve, reject) => {
       fs.readdir(svgDir, function(err, files) {
         if (err) reject(err);
         Promise.all(files.map(filename => readfile(filename)))
          .then(data => resolve(data))
          .catch(err => reject(err));
       });
      });
    }
    
    // 生成js文件
    readSvgs().then(data => {
      let svgFile = 'export default ' + JSON.stringify(Object.assign.apply(this, data));
      fs.writeFile(path.resolve(__dirname, './svgs.js'), svgFile, function(err) {
        if(err) throw new Error(err);
      })
    }).catch(err => {
        throw new Error(err);
      });

    这样生成了一个svgs.js文件。其结构是

    // svgs.js
    export default {
      'svgName1': 'xmlData1...',
      'svgName2': 'xmlData2...',
      ...
    }

    步骤3:封装Svg Component

    // Svg.js
    import React, { Component } from 'react';
    import {
      ViewStyle,
    } from 'react-native'
    import SvgUri from '../../lib/react-native-svg-uri';
    import svgs from '../../assets/svgs';
    
    export default class Svg extends Component<SvgProperties, void>{
      render() {
        const {
          iocn,
          color,
          size,
          style,
        } = this.props;
        let svgXmlData = svgs[this.props.icon];
    
        if (!svgXmlData) {
          let err_msg = `没有"${this.props.icon}"这个icon,请下载最新的icomoo并 npm run build-js`;
          throw new Error(err_msg);
        }
        return (
          <SvgUri
            width={size}
            height={size}
            svgXmlData={svgXmlData}
            fill={color}
            style={style}
          />
        )
      }
    }
     

    使用

    render() {
      return <Svg icon="ac_unit" size="40" fill="#ccc"/>
    }
    原文:https://www.jianshu.com/p/7db2bc62c5ed?from=timeline&isappinstalled=0

  • 相关阅读:
    为什么使用C#开发软件的公司和程序员都很少?
    使用Redis之前5个必须了解的事情
    这段代码为什么捕获不到异常呢?谁能给个解释,谢谢。
    git报错
    C# 常用类库(字符串处理,汉字首字母拼音,注入攻击,缓存操作,Cookies操作,AES加密等)
    你所不知道的 CSS 负值技巧与细节
    CSS 属性选择器的深入挖掘
    探秘 flex 上下文中神奇的自动 margin
    CSS 火焰?不在话下
    不可思议的纯 CSS 实现鼠标跟随效果
  • 原文地址:https://www.cnblogs.com/chenzxl/p/14656443.html
Copyright © 2020-2023  润新知