内容简介:图片资源( jpeg、png、svg、webp ... )作为与用户交互的界面元素,在客户端产品中起到了非常重要的角色作用。在应用开发中,移动端与PC的图片使用策略也有所不同。PC端较大的内存容量,快速的渲染能力使各类型图片资源都能得到较好的使用。而移动端由于设备内存,GPU渲染都与PC有较大差别,所以在App应用开发中,需要我们单独分析处理。今天我们聊聊在React Native开发中,如何优美的使用图片资源。 在 React Native 开发中,目前主流的图标解决方式大概有四种:基本图片格式是开发者最
图片资源( jpeg、png、svg、webp ... )作为与用户交互的界面元素,在客户端产品中起到了非常重要的角色作用。在应用开发中,移动端与PC的图片使用策略也有所不同。PC端较大的内存容量,快速的渲染能力使各类型图片资源都能得到较好的使用。而移动端由于设备内存,GPU渲染都与PC有较大差别,所以在App应用开发中,需要我们单独分析处理。今天我们聊聊在React Native开发中,如何优美的使用图片资源。 在 React Native 开发中,目前主流的图标解决方式大概有四种:
基本图片格式(png、jpeg)
基本图片格式是开发者最常用的一种图片资源,RN官方提供了在移动端适配的解决方案,直接使用 Image 标签就可以加载网络、本地图片。
【缺点】 需要引入多倍图(@2x / @3x)进行适配,使得 jsBundle 体积增大,内存占用的消耗比较明显。热更新时对流量(虽然你不在乎),影响较大。资产变更必须伴随二进制版本(apk | ipa)
Url
将图片保存在服务端,客户端以URL的方式进行加载。客户端不需要任何处理,例如在RN中加载网络图,只需要将URL传递给 Image 组件的 src props 。
【缺点】 缓存较为麻烦,可以依赖 react-native-fast-image 库。
IconFont (react-native-vector-icons)
熟悉Web开发的同学,对于 字体图标 绝对是不陌生的。基于此,开源库 react-native-vector-icons 实现了在RN平台的字体图标解决方案。这种方案简单,引进库和 .ttf 文件,就能使用字体图标了。
【缺点】 需要随app打包,文件小,使用便利,不用担心屏幕屏幕尺寸不能热更新,需要引入额外的库。
Svg
Svg 拥有体积小( Path ),可缩放特性,因此不需要适配屏幕的分辨率尺寸,并且有效降低移动端内存占用问题。同时完美支持bundle热更新
【缺点】 RN平台默认并不支持 Svg,幸运的是 react-native-svg 库实现了在RN移动应用中渲染 Svg 图标的能力。
方案分析
多倍图适配,.ttf 文件不能热更新的问题。现有的字体图标管理网站(iconfont、icomoo)也能生成svg文件。使得我们最终直接使用Svg。 react-native-svg 能对svg的标签解析成图片,如何将图片渲染成组件呢?第三方库 react-native-svg-uri 则能把svg文件的xml解析成 Component。迫不及待的集成,引入,运行。iOS完美的显示出来,而将 Android 进行 Release 打包过程中,Logcat抛出如下错误:
原因是在Android平台不支持直接加载 .svg 后缀的文件格式,只能允许加载 png
和 xml
格式的文件。我们打开.svg文件,可以看到如下内容:
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg t="1554188197278" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4579" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"> <defs> <style type="text/css"></style> </defs> <path d="M790.24975 1.022977H228.123876c-42.453546 0-77.234765 35.292707-77.234765 78.769231v870.553446c39.896104 0 72.11988 33.246753 72.11988 73.654346h35.292707c0-19.948052 15.856144-36.315684 35.804196-36.315684s35.804196 16.367632 35.804196 36.315684h35.804196c0-19.948052 15.856144-36.315684 35.804196-36.315684s35.804196 16.367632 35.804195 36.315684h35.804196c0-19.948052 15.856144-36.315684 35.804196-36.315684s35.804196 16.367632 35.804196 36.315684h35.804196c0-19.948052 15.856144-36.315684 35.804195-36.315684s35.804196 16.367632 35.804196 36.315684h35.292707c0-19.948052 15.856144-36.315684 35.804196-36.315684s35.804196 16.367632 35.804196 36.315684h35.804196c0-40.407592 32.223776-73.142857 71.608391-73.142857V79.280719C867.484515 35.804196 832.703297 1.022977 790.24975 1.022977z m-118.153846 339.628372l-86.953047 88.999001h45.522478c16.879121 0 30.177822 13.298701 30.177822 30.68931s-13.298701 30.689311-30.177822 30.689311h-91.044955v62.401598h91.044955c16.879121 0 30.177822 13.298701 30.177822 30.689311s-13.298701 30.689311-30.177822 30.689311h-91.044955v93.090909c0 17.390609-13.298701 30.689311-30.177823 30.689311s-30.177822-13.298701-30.177822-30.689311v-93.090909H388.21978c-10.22977 0-20.971029-6.649351-26.085914-15.856144s-5.114885-21.482517 0-30.689311c5.114885-10.741259 15.856144-15.856144 26.085914-15.856144h91.044955V489.494505H388.21978c-16.879121 0-30.177822-13.298701-30.177822-30.68931s13.298701-30.689311 30.177822-30.689311h48.07992L345.254745 341.674326c-7.672328-8.183816-10.22977-19.948052-7.672327-30.689311s11.764236-19.948052 21.994006-22.505495c10.22977-4.091908 21.994006 0 30.177822 8.183817l119.688311 122.245754L629.130869 296.663337c7.672328-9.206793 19.436563-11.764236 30.177822-9.206794 10.22977 2.557443 19.436563 11.764236 21.994006 22.505495 2.557443 10.741259-1.022977 22.505495-9.206793 30.689311z" fill="#FF6F5A" p-id="4580"> </path> </svg>复制代码
可以看到,其实 Svg 文件就是以path路径来绘制图标的。所以我们可以放弃 require svg 文件的方式,直接解析 svg 文件中的path 即可。同时也解决了减少 svg 占用空间,频繁 require 静态文件减慢速度的问题。 我们可以用脚本来将 svg文件 批量生成 Path 字符串,然后通过 react-native-svg-uri 来解析 Path xml。同时该库作者也考虑到 Android 的问题,为开发者提供了通过 svg path 字符串渲染图标的Api: svgXmlData 。
【注意】react-native-svg-uri 更新太慢,建议不通过 npm 或 yarn 安装,直接复制文件在项目中使用,避免版本问题。
核心实现
通过上面的解析,实现流程分为如下三步:
(1)下载Svg文件
(2)解析所有Svg文件,将svg的path统一存放在 js 文件中
(3)封装 svg 组件,通过 svgXmlData 加载svg path
可以看出第二步的实现起到来承前启后的重要性,我们来看下核心代码。
解析
/** * 读取svg文件 * @param {*} svgFileName svg文件, 例如 home-icon.svg * @returns { 'home-icon': '<svg>... <path>...</path> ...</svg>' } */ function readSvgFile(svgFileName) { return new Promise((resolve, inject) => { readFile(path.join(svgFileDir, svgFileName), 'utf8', (error, svgFile) => { // eslint-disable-next-line no-useless-escape const svgPath = svgFile.replace(/<\?xml.*?\?>|<\!--.*?-->|<!DOCTYPE.*?>/g, ''); if (error) { inject(error); } resolve({ [svgFileName.slice(0, svgFileName.lastIndexOf('.'))]: svgPath, }); }); }); } /** * 读取svg文件夹目录所有svg文件 * @returns { 'home-icon': '<path>...</path>', 'xxx': '<path>...</path>' ... } */ function readSvgDir() { return new Promise((resolve, inject) => { readdir(svgFileDir, (error, svgFiles) => { if (error) { inject(error); } // svgFiles: string[] Promise.all(svgFiles.map((svgFileName) => readSvgFile(svgFileName))) .then((data) => resolve(data)) .catch((err) => inject(err)); }); }); } /** * 生成 .js 文件 */ readSvgDir().then((data) => { const svgFile = `export default { ${ data.map((item, index) => `${Object.keys(item)[0]}: '${Object.values(item)[0]}'\n`) } }`; writeFile(path.resolve(__dirname, `./${GENERATE_SVG_FILE_NAME}`), svgFile, (err) => { if (err) { throw new Error(err); } }); }).catch((error) => { throw new Error(error); });复制代码
从上述代码可以看到,我们通过读取遍历svg文件夹下的所有svg文件,拿到<svg>... <path>...</path> ...</svg>的字符串,并将其生成js文件统一管理。最终生成的文件内容如下
export default { iconImage: '<svg class="icon" width="128px" height="128.00px" viewBox="0 0 />',};复制代码
封装 SvgIcon 组件
/** * svg 图片组件 * @export * @class SvgIcon * @extends {PureComponent} */ import React, { PureComponent } from 'react'; import { View } from 'react-native'; import PropTypes from 'prop-types'; import SvgUri from './SvgUri'; import svgXmlData from './svgXmlData'; export default class SvgIcon extends PureComponent { static propTypes = { style: PropTypes.object, /* eslint-disable react/require-default-props */ color: PropTypes.object, size: PropTypes.shape( { width: PropTypes.number.isRequired, height: PropTypes.number.isRequired, } ).isRequired, icon: PropTypes.string.isRequired, } static defaultProps = { style: {}, } render() { const { size, color, style, icon, } = this.props; const svgXmlPath = svgXmlData[icon]; // eslint-disable-next-line no-nested-ternary return svgXmlData ? color ? ( <SvgUri fill={color} style={style} width={size.width} height={size.height} svgXmlData={svgXmlPath} /> ) : ( <SvgUri style={style} width={size.width} height={size.height} svgXmlData={svgXmlPath} /> ) : <View />; } }复制代码
使用
<SvgIcon icon={iconImage} style={{ marginRight: 5 }} size={{ width: 26, height: 26 }}/>复制代码
通过以上实现,我们就优美的解决了图片资源加载渲染问题。详细代码已上传到GitHub: react-native-svg-icon
WebP
默认情况下 React Native 是不支持 GIF 和 WebP 格式的。Android 需要在 android/app/build.gradle
文件中根据需要手动添加以下模块:
dependencies { // 如果你需要支持Android4.0(API level 14)之前的版本 compile 'com.facebook.fresco:animated-base-support:1.10.0' // 如果你需要支持GIF动图 compile 'com.facebook.fresco:animated-gif:1.10.0' // 如果你需要支持WebP格式,包括WebP动图 compile 'com.facebook.fresco:animated-webp:1.10.0' compile 'com.facebook.fresco:webpsupport:1.10.0' // 如果只需要支持WebP格式而不需要动图 compile 'com.facebook.fresco:webpsupport:1.10.0' }复制代码
iOS需要依赖第三方平台来实现Webp的加载,如:react-native-webp-supprot 。推荐大家看下这篇文章: React Native + WebP: Reducing bundle + binary sizes, increase speed with .webp image format
以上所述就是小编给大家介绍的《React Native图片资源使用的优美方案》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 工程大小优化之图片资源
- 前端解决第三方图片防盗链的办法 - html referrer 访问图片资源 403 问题
- 使用python对cocos2dx的手游图片资源进行加密
- js如何阻止图片的其他资源的加载(DOMContentLoaded)
- Nuxt资源文件夹,别名,图片url和css
- 【iOS 开发】将图片、声音等资源文件打包为 Bundle 的方法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Art and Science of Java
Eric Roberts / Addison-Wesley / 2007-3-1 / USD 121.60
In The Art and Science of Java, Stanford professor and well-known leader in CS Education Eric Roberts emphasizes the student-friendly exposition that led to the success of The Art and Science of C. By......一起来看看 《The Art and Science of Java》 这本书的介绍吧!