开发语言: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都显示了我们画的圆。
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。
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}
/>
);
}
}
然后我们就可以看到被缩短了一半的线了。