如何在React Native中显示SVG文件?

204

我想展示一些svg文件,但是我找不到展示方法。我尝试使用react-native-svgImageUse组件,但它们并不能用于展示svg。我也尝试了本地方法,但很难仅仅展示svg图像。

示例代码:

import Svg, {
  Use,
  Image,
} from 'react-native-svg';

<View>
  <Svg width="80" height="80">
     <Image href={require('./svg/1f604.svg')} />
  </SvgRn>
</View>

我知道React Native基本上不支持SVG,但我认为有人用巧妙的方法解决了这个问题(带/不带React-Native-SVG)。


你不能使用"use"来显示整个文件,你需要使用"image"。 - Robert Longson
是的,我也试过了 @RobertLongson,但它还是不起作用。 - the_bluescreen
我尝试过,但React Native的View组件不支持在CSS样式中使用backgroundImage属性。@danielarend - the_bluescreen
我不确定为什么要使用SVG包装器来包装SVG图像。 - Robert Longson
@RobertLongson 因为RN的Image组件不支持SVG文件。当我尝试使用"react-native-svg"组件时,需要将代码放在SVG包装器中。 - the_bluescreen
显示剩余2条评论
24个回答

152

2
那个组件怎么使用?你能分享一下代码吗? - Indranil Dutta
3
当我尝试使用你的解决方案时,出现了这个错误:Uncaught Error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function but got: object。请问您能帮忙解决吗? - ThinkAndCode
3
如果您在使用此方法时遇到问题,请确保已安装最新版本的 react-native-svg 包。同时,请运行以下命令以链接您的包:react-native link react-native-svg - connect2Coder
3
这是一个实现SVG文件的漫长过程,最好使用以下建议的https://github.com/kristerkari/react-native-svg-transformer。 https://dev59.com/B1kT5IYBdhLWcg3wRNit#55604442 - hefgi
2
当你有数百个图标需要设计时,这真是一场噩梦。 - ICW
显示剩余11条评论

26

我在这里发布了另一种解决方案(react-native-vector-icons)。这种方法使用矢量字体(SVG)而不是SVG文件。

PS:react-native-vector-icons是处理react-native中SVG的最佳方法,它也适用于iOS和Android。您可以更改矢量图标的颜色和大小。

如果您想直接将svg插入应用程序中,可以尝试第三方库:react-native-svg。在Github上有超过3k个星标,是其中之一的最佳方法。

使用npm安装以下任一项:

然后使用下面的命令将其链接到原生应用:

react-native link react-native-svg

使用react-native-svg-uri的示例:

import * as React from 'react';
import SvgUri from 'react-native-svg-uri'; // SVG Package
import testSvg from './test.svg';          // SVG File

export default () => (
  <SvgUri
    width="200"
    height="200"
    svgXmlData={testSvg}
  />
);

它会报错“无法将没有测量函数的CSS节点的子节点添加到没有测量函数的节点中”。 - Pulkit Aggarwal
1
看这里我发布的答案,使用字体而不是SVG,这是更好的解决方案:https://dev59.com/O6rka4cB1Zd3GeqPjMuw#49952050 - Cassio Seffrin
5
这个库非常慢。它将每个 SVG 包装在自己的 Webview 中。 - JP_
2
谢谢,这是最快的解决方案,但是我使用了source={testSvg}而不是svgXmlData={testSvg},效果非常好。再次感谢。 - Andris Laduzans
1
@Omarbakhsh 我建议你尝试这个 https://dev59.com/O6rka4cB1Zd3GeqPjMuw#49952050 - Cassio Seffrin
显示剩余4条评论

25

安装react-native-svg-transformer

npm i react-native-svg-transformer --save-dev

我正在使用以下方式使用SVG,它能正常工作

import LOGOSVG from "assets/svg/logo.svg"

在渲染中

<View>
  <LOGOSVG 
    width="100%"
    height="70%"
  />
</View>

当我从图像文件夹导入SVG文件HEARTSVG时,它显示错误。而导入PNG文件没有错误。有什么建议吗? - Rakesh

18

我尝试了上述所有解决方案以及堆栈之外的其他解决方案,但都没有起作用。 最终,在长时间的研究之后,我为我的expo项目找到了一个解决方案。

如果你需要在expo中使用它,一个变通的方法可能是使用https://react-svgr.com/playground/并将props的扩展移动到G元素而不是SVG根元素,就像这样:

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

function SvgComponent(props) {
  return (
    <Svg viewBox="0 0 511 511">
      <G {...props}>
        <Path d="M131.5 96c-11.537 0-21.955 8.129-29.336 22.891C95.61 132 92 149.263 92 167.5s3.61 35.5 10.164 48.609C109.545 230.871 119.964 239 131.5 239s21.955-8.129 29.336-22.891C167.39 203 171 185.737 171 167.5s-3.61-35.5-10.164-48.609C153.455 104.129 143.037 96 131.5 96zm15.92 113.401C142.78 218.679 136.978 224 131.5 224s-11.28-5.321-15.919-14.599C110.048 198.334 107 183.453 107 167.5s3.047-30.834 8.581-41.901C120.22 116.321 126.022 111 131.5 111s11.28 5.321 15.919 14.599C152.953 136.666 156 151.547 156 167.5s-3.047 30.834-8.58 41.901z" />
        <Path d="M474.852 158.011c-1.263-40.427-10.58-78.216-26.555-107.262C430.298 18.023 405.865 0 379.5 0h-248c-26.365 0-50.798 18.023-68.797 50.749C45.484 82.057 36 123.52 36 167.5s9.483 85.443 26.703 116.751C80.702 316.977 105.135 335 131.5 335a57.57 57.57 0 005.867-.312 7.51 7.51 0 002.133.312h48a7.5 7.5 0 000-15h-16c10.686-8.524 20.436-20.547 28.797-35.749 4.423-8.041 8.331-16.756 11.703-26.007V503.5a7.501 7.501 0 0011.569 6.3l20.704-13.373 20.716 13.374a7.498 7.498 0 008.134 0l20.729-13.376 20.729 13.376a7.49 7.49 0 004.066 1.198c1.416 0 2.832-.4 4.07-1.2l20.699-13.372 20.726 13.374a7.5 7.5 0 008.133 0l20.732-13.377 20.738 13.377a7.5 7.5 0 008.126.003l20.783-13.385 20.783 13.385a7.5 7.5 0 0011.561-6.305v-344a7.377 7.377 0 00-.146-1.488zM187.154 277.023C171.911 304.737 152.146 320 131.5 320s-40.411-15.263-55.654-42.977C59.824 247.891 51 208.995 51 167.5s8.824-80.391 24.846-109.523C91.09 30.263 110.854 15 131.5 15s40.411 15.263 55.654 42.977C203.176 87.109 212 126.005 212 167.5s-8.824 80.391-24.846 109.523zm259.563 204.171a7.5 7.5 0 00-8.122 0l-20.78 13.383-20.742-13.38a7.5 7.5 0 00-8.131 0l-20.732 13.376-20.729-13.376a7.497 7.497 0 00-8.136.002l-20.699 13.373-20.727-13.375a7.498 7.498 0 00-8.133 0l-20.728 13.375-20.718-13.375a7.499 7.499 0 00-8.137.001L227 489.728V271h8.5a7.5 7.5 0 000-15H227v-96.5c0-.521-.054-1.03-.155-1.521-1.267-40.416-10.577-78.192-26.548-107.231C191.936 35.547 182.186 23.524 171.5 15h208c20.646 0 40.411 15.263 55.654 42.977C451.176 87.109 460 126.005 460 167.5V256h-.5a7.5 7.5 0 000 15h.5v218.749l-13.283-8.555z" />
        <Path d="M283.5 256h-16a7.5 7.5 0 000 15h16a7.5 7.5 0 000-15zM331.5 256h-16a7.5 7.5 0 000 15h16a7.5 7.5 0 000-15zM379.5 256h-16a7.5 7.5 0 000 15h16a7.5 7.5 0 000-15zM427.5 256h-16a7.5 7.5 0 000 15h16a7.5 7.5 0 000-15z" />
      </G>
    </Svg>
  );
}

export default function App() {
  return (
    <SvgComponent width="100%" height="100%" strokeWidth={5} stroke="black" />
  );
}

2
这对我也很好用。我们可以通过在浏览器中打开SVG文件并查看页面源代码来轻松获取SVG文件的路径,然后直接使用该路径,并将<path />标签替换为react-native-svg <Path />。非常感谢! - Rakesh
我不得不为包装的“View”设置“width”和“height”,否则最简单和直接的方法是,因为你基本上使用常规的<svg>,只需用来自react-native-svg的标签替换标签,就像@Rakesh所说的那样! - jave.web

15

以下是我在2022年发现适用于仍然遇到问题的人的方法,使用的是React Native版本0.63.4和React-Native-Svg版本^12.1.0,你也许可以尝试在其他版本中使用此方法,但请务必首先查阅库的文档:

  1. 通过运行以下命令安装react-native-svg-transformeryarn add react-native-svg-transformer --dev 或者如果你更喜欢使用npm,则可以运行 npm i react-native-svg react-native-svg-transformer --save-dev

  2. 通过运行以下命令安装babel-plugin-inline-importyarn add babel-plugin-inline-import --dev

  3. 你需要更新你的metro.config.js文件,使其看起来像这样:

const { getDefaultConfig } = require('metro-config');

module.exports = (async () => {
  const {
    resolver: { sourceExts, assetExts }
  } = await getDefaultConfig();
  return {
    transformer: {
      babelTransformerPath: require.resolve('react-native-svg-transformer'),
      getTransformOptions: async () => ({
        transform: {
          experimentalImportSupport: false,
          inlineRequires: false
        }
      })
    },
    resolver: {
      assetExts: assetExts.filter(ext => ext !== 'svg'),
      sourceExts: [...sourceExts, 'svg']
    }
  };
})();

  1. 确保像这样将svg文件导入到您的组件中:import CreditCard from '../assets/CreditCard'; 请注意,我没有将.svg文件扩展名添加到导入中,因为在运行时它会给我带来错误view config getter callback react-native-svg,但删除它似乎使其顺利运行。您可以将文件以此方式作为jsx元素添加,就像这样<CreditCard />

  2. 最后,通过在mac上使用^Ctrl + C停止它,然后使用此命令重新启动它yarn start:dev --reset-cache并重新安装应用程序。


12

你可以通过简单的方法来完成这个操作

首先,你需要进行安装:

  1. npm install -s react-native-svg
  2. react-native link react-native-svg
  3. npm install -s react-native-svg-transformer

然后,你需要在你的 metro.config.js 文件中添加以下代码:

const { getDefaultConfig } = require("metro-config");
module.exports = (async () => {
  const {
    resolver: { sourceExts, assetExts }
  } = await getDefaultConfig();
  return {
    transformer: {
      babelTransformerPath: require.resolve("react-native-svg-transformer")
    },
    resolver: {
      assetExts: assetExts.filter(ext => ext !== "svg"),
      sourceExts: [...sourceExts, "svg"]
    }
  };
})();

接下来,在您的根目录中创建一个名为declarations.d.js的新文件,并使用以下代码:

declare module "*.svg" {
  import { SvgProps } from "react-native-svg";
  const content: React.FC<SvgProps>;
  export default content;
}

最后,这是一个重要的方法

import USER from "../../assets/icons/user.svg"

同时,这也适用于JSX。

<USER width="100%" height="100%"/>


12

在尝试了许多方法和库之后,我决定使用Glyphs或这个教程创建一个新的字体,并将我的SVG文件添加到其中,然后使用“Text”组件与我的自定义字体。

希望这能帮助那些在React Native中遇到相同SVG问题的人。


我认为你是正确的,字体族可能是将简单SVG导入React Native最简单的方式。 - Joe Lloyd
这是一个关于该主题的不错教程:https://blog.bam.tech/developper-news/add-custom-icons-to-your-react-native-application。需要使用[Vector Icons](https://github.com/oblador/react-native-vector-icons) Node包。 - Rafa Viotti
如果您需要导入多色SAG文件,则此解决方案无效。 - Joe Aspara
1
我已经尝试过使用icomoon的解决方案,但它并没有奏效,而且他们的支持也不积极。而fontello正在改变我的SVG文件。 - Siraj Alam

9

SVG不支持原生应用程序直接使用,为了显示SVG图像,我们需要借助第三方模块的帮助。

请按照以下步骤进行操作:

步骤1。安装react-native-svgreact-native-svg-transformer模块。

npm i react-native-svg react-native-svg-transformer

步骤2:如果不存在,则添加文件metro.config.js

const { getDefaultConfig } = require("metro-config");

module.exports = (async () => { 
    const {  
        resolver: { 
            sourceExts, 
            assetExts 
        }  
    } = await getDefaultConfig(); 

    return {
        transformer: {      
            babelTransformerPath: require.resolve("react-native-svg-transformer")    
        },    
        resolver: {
            assetExts: assetExts.filter(ext => ext !== "svg"),
            sourceExts: [...sourceExts, "svg"]    
        }};
})();

步骤 3:将 SVG 文件用作 React 组件

import Invest from '../assets/invest.svg'; // import SVG

return (
        <View>
            <Invest /> // Use SVG as component
        </View>
    )

1
非常感谢您的共享,但我注意到 react-native-svg-transformer 必须作为开发依赖项进行安装,就像您安装的那样: 首先:yarn add react-native-svgnpm i --save react-native-svg 然后:yarn add react-native-svg-transformer -Dnpm i --dev react-native-svg-transformer - Micessien

4

我曾经遇到相同的问题。我使用了找到的这个解决方案:React Native 展示来自文件的 SVG

这个解决方案并不完美,今天我再次进行评估,因为它在Android上的性能表现要差很多。


其实这是一个有创意的答案,但它并不能帮助我的问题 :) 因为我将使用图标列表(10个或更多的SVG图标),所以如果我使用这个方法,性能可能会非常糟糕。你觉得呢? - the_bluescreen
我在一个页面上呈现了10-15个SVGs。iOS没有人抱怨,但Android却有人抱怨。在iOS上,有0.1-0.3秒的延迟(加载前的一瞬间白屏)。 在Android上可能需要1秒钟,甚至有时根本无法加载。最后,我将我的SVG文件检入,然后编写了一个脚本,使用svg2png将它们转换成完全正确大小的PNG文件。 然后使用<Image>与这些PNGs。 鉴于react native中SVG的当前状态,如果你不能忍受这种解决方法,那么这是你最好的选择,因为目前还没有SVG正常工作的预计完成时间。 - Sledge Hammer

4

使用https://github.com/kristerkari/react-native-svg-transformer

在这个包中提到,React Native v0.57及以下版本不支持.svg文件,因此请使用.svgx扩展名来保存svg文件。

对于Web或React-Native-Web,请使用https://www.npmjs.com/package/@svgr/webpack


要在React-Native版本0.57及以下版本中使用react-native-svg-uri渲染svg文件,您需要将以下文件添加到根项目中

注:更改扩展名svgsvgx

步骤1:将transformer.js文件添加到项目根目录中

// file: transformer.js

const cleanupSvg = require('./cleanup-svg');

const upstreamTransformer = require("metro/src/transformer");

// const typescriptTransformer = require("react-native-typescript-transformer");
// const typescriptExtensions = ["ts", "tsx"];

const svgExtensions = ["svgx"]

// function cleanUpSvg(text) {
//   text = text.replace(/width="([#0-9]+)px"/gi, "");
//    text = text.replace(/height="([#0-9]+)px"/gi, "");
//    return text;
// }

function fixRenderingBugs(content) {
  // content = cleanUpSvg(content); // cleanupSvg removes width and height attributes from svg
  return "module.exports = `" + content + "`";
}


module.exports.transform = function ({ src, filename, options }) {
  // if (typescriptExtensions.some(ext => filename.endsWith("." + ext))) {
  //  return typescriptTransformer.transform({ src, filename, options })
  // }

  if (svgExtensions.some(ext => filename.endsWith("." + ext))) {
    return upstreamTransformer.transform({
      src: fixRenderingBugs(src),
      filename,
      options
    })
  }

  return upstreamTransformer.transform({ src, filename, options });
}


步骤二:将 rn-cli.config.js 添加到项目根目录
module.exports = {
    getTransformModulePath() {
      return require.resolve("./transformer");
    },
    getSourceExts() {
      return [/* "ts", "tsx", */ "svgx"];
    }
  };

上述解决方案也适用于生产应用程序 ✅

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接