ReactNative混合开发-4 使用svg图片

开发语言:ReactNative 0.59.5
开发环境:VSCode

我们可以在ReactNative中使用SVG图片亦或将SVG的内容当作一个组件来使用,如果我们想使用SVG的语法或直接使用SVG的内容我们需要用到react-native-svg,而通过资源的方式加载svg文件我们需要额外用到react-native-svg-url。本文只使用前者。

1、ReactNativeSVG环境搭建

参考文章:react-native-svg

1.1、安装react-native-svg

控制台输入指令

npm install react-native-svg --save

由于react-native-svg与react native类似,我们也需要在原生端配置相应的解析器才可以在混编程序中正确的解析svg语法。

1.2、IOS项目链接(使用CocoaPods)

在Podfile中添加下面一句话,注意node_modules的路径。

pod 'RNSVG', :path => '../../node_modules/react-native-svg'

然后重新执行pod install即可。

1.3、Android项目链接

在settings.gradle中增加下面一句话,注意node_modules的路径。

include ':react-native-svg'
project(':react-native-svg').projectDir = new File(rootProject.projectDir,  '../../node_modules/react-native-svg/android')

在app/build.gradle中增加下面一句话,注意添加在dependencies内。

dependencies {
    ...
    implementation project(':react-native-svg')
}

在引用完成后重新编译一下,然后,在我们创建ReactInstanceManager时候,额外添加一个svgPackage,以我自己的代码为例。

private static final ReactInstanceManager mReactInstanceManager = ReactInstanceManager.builder()
            .setApplication(MyApplication.getInstance())
            .setBundleAssetName("index.android.bundle")
            .setJSMainModulePath("Scripts/index")
            .addPackage(new MainReactPackage())
            .addPackage(new SvgPackage()) //添加svgPackage
            .setUseDeveloperSupport(BuildConfig.DEBUG)
            .setInitialLifecycleState(LifecycleState.RESUMED)
            .setCurrentActivity(MyApplication.getInstance().getCurrentActivity())
            .build();

2、JS脚本内使用

现在,我们可以在JS脚本内使用svg的简单语法来绘制一些简单的图案,比如画个圆。

import React, { Component } from 'react'
import { NativeModules } from 'react-native'
import Svg,{
    Circle
} from 'react-native-svg';


export default class FrameText extends Component {

    render() {
        return (
            <Svg
                height="100"
                width="100"
            >
                <Circle
                    cx="50"  
                    cy="50"  
                    r="45"  
                    stroke="black"  
                    strokeWidth="2.5" 
                    fill="red"   
                />
            </Svg>
        );
    }
}
// 整体js模块的名称
export { FrameText } 

然后运行我们的IOS和Android代码,可以看到两个demo都显示了我们画的圆。

IOS
Android

3、SVG图片转换为ReactNative组件

当然,在现实的工作中,我们基本不会自己手动使用代码写一个svg,通常都是美工通过ps或者其他工具导出一个svg文件给我们使用,我们可以通过文章开头提到的react-native-svg-url来加载他们,但是svg的优势是实时的绘制,我们可以向svg增加一些我们想要的属性来控制svg的某些子节点的移动,旋转,甚至我们可以利用svg来实现动画效果。这时我们就要将svg图片转换为一个可调用的组件来完成这一需求了。

以此svg图片为例,svg的原始代码如下:

<svg
    xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.87 61.33">
    <defs>
        <style>.cls-1{fill:#d81f1e;}.cls-2{fill:#75161c;}.cls-3{fill:#a82024;}.cls-4{fill:none;stroke:#2c2e2e;stroke-miterlimit:10;stroke-width:0.31px;}</style>
    </defs>
    <title>资源 45</title>
    <g id="图层_2" data-name="图层 2">
        <g id="pic">
            <g id="盒">
                <rect id="盒右" class="cls-1" x="3.93" y="49.14" width="11.94" height="12.18"/>
                <polygon id="盒左" class="cls-2" points="3.94 61.33 0 55.56 0 43.37 3.94 49.14 3.94 61.33"/>
                <polygon id="盒上" class="cls-3" points="15.87 49.14 3.94 49.14 0 43.41 11.94 43.41 15.87 49.14"/>
            </g>
            <g id="线">
                <line id="线4" class="cls-4" x1="12.49" x2="12.49" y2="48.98"/>
                <line id="线3" class="cls-4" x1="9.46" x2="9.46" y2="43.58"/>
                <line id="线1" class="cls-4" x1="2.59" x2="2.59" y2="43.58"/>
                <line id="绳子4-2" data-name="线2" class="cls-4" x1="6.03" x2="6.03" y2="48.98"/>
            </g>
        </g>
    </g>
</svg>

我们无法直接在React Native中直接使用这段代码,代码中每一个节点类都是小写,例如g,title等等,而且代码中定义了defs来定义了颜色样式,但react-native-svg无法识别defs,所以我们需要将这段代码转换成React Native可识别的组件。这里我们使用SVGR来完成这个需求。

3.1、SVGR的使用

正如SVGR的介绍语 Transform SVGs into React components ,它可以将SVG转化成React使用的组件,而且提供在线版,在线版地址SVGR PlayGround
首先,我们将上面的代码复制到SVGR PlayGround的左边,它会自动开始转换,转换后的组件会在右边显示,为了转换出能在React Native中使用的组件,我们还需要设置一些转换参数。

  • 在Global中选中React Native
  • 在SVGO中选中Enable
  • 在SVGO的config选项填入如下配置属性(这点非常重要,否则某些defs不会被转换!)
{
    "plugins": [{
        "inlineStyles": {
        "onlyMatchedOnce": false
        }
    }]
}

  • 在Prttier中选中Enable

在配置完这些属性后,后边转换完成的组件就可以直接使用了

import React from 'react'
import Svg, { G, Path } from 'react-native-svg'

const SvgComponent = props => (
  <Svg viewBox="0 0 15.87 61.33" {...props}>
    <G data-name="\u56FE\u5C42 2">
      <Path fill="#d81f1e" d="M3.93 49.14h11.94v12.18H3.93z" />
      <Path fill="#75161c" d="M3.94 61.33L0 55.56V43.37l3.94 5.77v12.19z" />
      <Path fill="#a82024" d="M15.87 49.14H3.94L0 43.41h11.94l3.93 5.73z" />
      <G fill="none" stroke="#2c2e2e" strokeMiterlimit={10} strokeWidth={0.31}>
        <Path d="M12.49 0v48.98M9.46 0v43.58M2.59 0v43.58" />
        <Path data-name="\u7EBF2" d="M6.03 0v48.98" />
      </G>
    </G>
  </Svg>
)

export default SvgComponent

我们在脚本中使用这个组件,注意使用组件时需要给出高宽。

import React, { Component } from 'react'
import Svg, { G, Path } from 'react-native-svg'

const SvgComponent = props => (
  <Svg viewBox="0 0 15.87 61.33" {...props}>
    <G data-name="\u56FE\u5C42 2">
      <Path fill="#d81f1e" d="M3.93 49.14h11.94v12.18H3.93z" />
      <Path fill="#75161c" d="M3.94 61.33L0 55.56V43.37l3.94 5.77v12.19z" />
      <Path fill="#a82024" d="M15.87 49.14H3.94L0 43.41h11.94l3.93 5.73z" />
      <G fill="none" stroke="#2c2e2e" strokeMiterlimit={10} strokeWidth={0.31}>
        <Path d="M12.49 0v48.98M9.46 0v43.58M2.59 0v43.58" />
        <Path data-name="\u7EBF2" d="M6.03 0v48.98" />
      </G>
    </G>
  </Svg>
)


export default class FrameText extends Component {

    render() {
        return (
            <SvgComponent
                height="200"
                width="200"
            />
        );
    }
}
// 整体js模块的名称
export { FrameText } 

运行我们的IOS和Android代码,可以看到两个demo都显示了这2个SVG。

IOS
Android

3.2、SVGR的安装

由于这个在线版并不是很稳定,我们也可以在本机安装SVGR在本地进行转换,转换过程如下:

原svg ---使用svgo压缩--> 压缩后的svg ---使用svgr转换为组件--> React Native组件

首先使用如下命令安装svgo。

npm install -g svgo

安装完成后会看见如下提示:

/usr/local/bin/svgo -> /usr/local/lib/node_modules/svgo/bin/svgo
+ svgo@1.2.2
added 49 packages from 83 contributors in 1.985s

注意路径:/usr/local/lib/node_modules/svgo/bin/svgo ,然后我们进入这个路径,在plugins文件夹中找到inlineStyles.js文件,修改代码。

exports.params = {
    onlyMatchedOnce: false,//原本为true,现在改成false,用于转换所有的defs文件
    removeMatchedSelectors: true,
    useMqs: ['', 'screen'],
    usePseudos: ['']
};

保存文件后,使用如下命令行压缩svg文件。

svgo XXX.svg 

完成压缩后会看到提示。

XXX.svg:
Done in 46 ms!
0.877 KiB - 48.1% = 0.455 KiB

然后使用如下命令生成React Native组件。

npx @svgr/cli --native XXX.svg

最后我们可以在控制台看到和在线版完全一样的React Native组件了。

3.3、给组件添加属性

之前也有提到,SVG可以实时的绘制,我们也可以通过属性来改变上述组件的某些节点的位置或者大小,下面我们使用属性来缩放图片中的线。

首先修改组件中的代码,暴露一个sHeight属性供外部属性,它可以用来改变g节点的高度缩放

const SvgComponent = props => (
   ...
   <G fill="none" stroke="#2c2e2e" strokeMiterlimit={10} strokeWidth={0.31}  scaleY={props.sHeight}>
   ...
  )

然后在代码中使用这个属性。

export default class FrameText extends Component {

    render() {
        return (
            <SvgComponent
                height="200"
                width="200"
                sHeight={0.5}
            />
        );
    }
}

然后我们就可以看到被缩短了一半的线了。

IOS
Android
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345