当前位置: 首页 > 知识库问答 >
问题:

如何用react-native-svg为width,height和viewBox找到正确的值

储峻
2023-03-14

我一直在尝试做一些看起来很容易的事情,但是我已经尝试了几个小时了,也找不到解决的办法。

我有一个SVG需要在屏幕上。它来自设计师,具有这些维度:

<Svg width="354px" height="190px" viewBox="0 0 354 190">...</Svg>

在React Native中,这将位于容器内部,SVG需要获取屏幕的全宽度,我从以下内容获取:

Dimensions.get("window").width

我的问题是,我还没有找到一种方法来缩放SVG以获得100%的屏幕宽度,找出正确的高度(或者自动设置高度的方法),并保留纵横比。我已经尝试了很多事情,包括玩容器的aspectRatio样式和它的高度(或者根本不设置高度)。每当我发现一些“比例”的工作,我尝试在不同的设备与不同的屏幕宽度,它看起来一点也不好看(裁剪,比屏幕宽度小,等等)。

我觉得SVG(react-native-svg)中的preserveAspectRatio属性与aspectRatio样式有些冲突。我完全失去了保留的aspectratio,我没有找到一种方法使它缩放而不被裁剪。

有没有人知道如何做到这一点?

这是我的最后一段代码,它返回了一个显示SVG的热图组件,但是尽管它有正确的高度,但SVG的一部分从右边离开了屏幕(看起来被裁剪了,因为它太宽了):

const windowWidth = Dimensions.get("window").width;

const getSVGRootProps = ({ width, height }) => ({
  width: "100%",
  height: "100%",
  viewBox: `0 0 ${width} ${height}`,
  preserveAspectRatio: "xMinYMin meet",
});

const FieldShape = () => {
  const width = 354; // Original width
  const height = 190; // Original height
  const aspectRatio = width / height;
  // adjusted height = <screen width> * original height / original width
  const calculatedHeight = (windowWidth * height) / width;
  const fieldStyles = {
    width: windowWidth,
    height: calculatedHeight,
    aspectRatio,
  };

  return (
    <View style={fieldStyles}>
      <Svg {...getSVGRootProps({ windowWidth, calculatedHeight })}>
      ...
      </Svg>
    </View>
  );
};

const HeatMap = () => {
  return <FieldShape />;
};

这就是结果:

共有1个答案

王豪
2023-03-14

我已经找到了解决方案,我将它发布在这里,以防有人在react native和SVG中遇到同样的问题。基本上,如果您试图获取一个SVG文件,并将其转化为一个包含“动态”部分的组件(例如基于数据以编程方式为路径设置颜色,或显示SVG文本),那么您可能会遇到这个问题。

我所做的是使用SVGR将原始SVG转换为react原生组件(带有react-native-svg)。然后我只是根据需要用变量(来自道具)替换硬编码数据。它看起来不错,但我有一个问题的组件的大小。我找不到一个一致的方法来显示它在不同的设备大小和分辨率。这看起来很容易,但我试了几个小时,结果在每个屏幕尺寸上都不一样。在问了这个问题并开了一个关于react-native-svg repo的问题之后,我没有得到任何答案,也没有任何线索(没有责备任何人,只是说这可能不是很多人遇到的事情)。所以我挖了又挖,终于找到了Lea Verou的这篇文章,她在里面谈到了绝对和相对SVG路径。这让我想,也许我有这么多问题试图找到完美的大小公式,因为我的路径不是相对的,而是绝对的。所以我尝试了heyzeuss的这个jsfiddle,粘贴我的(原始)SVG代码,然后复制结果。我将结果粘贴到这个方便的SVGR playground(SVG到JS)工具中,然后我更改了一些位来实现我的目标:

  • 我希望我的SVG获得全屏的宽度,宽度和高度相应地缩放。

所以这就是我改变的:

// SVG's original size is 519 width, 260 height
// <Svg width="519" height="260" viewBox="0 0 519 260">...</Svg>
// I also added a container, which enforces the aspect ratio
const originalWidth = 519;
const originalHeight = 260;
const aspectRatio = originalWidth / originalHeight;
const windowWidth = Dimensions.get("window").width;
return (
    <View style={{ width: windowWidth, aspectRatio }}>
        <Svg 
            width="100%" 
            height="100%" 
            viewBox={`0 0 ${originalWidth} ${originalHeight}`}>
        ...
        </Svg>
    </View>
)

在此过程中我学到了一些东西,例如,create-react-app中包含了一个@svgr/cli,并且在我的react-native项目中也可用,而不需要安装任何额外的东西,因此它也必须与原始依赖项捆绑在一起。您可以运行此命令,它将把文件夹中的单个文件或所有文件从.svg转到React组件:

npx @svgr/cli [-d out-dir] [--ignore-existing] [src-dir]

用于将绝对路径转换为亲属路径的脚本是这个名为snap.svg的库的一部分,但您只需要它的1%(snap.path.toRelative)。我正在考虑有一个小工具,它可以处理svg文件中的所有路径,并应用这种转换。老实说,我已经处理SVG文件很多年了,但我从未真正了解过它在内部的工作方式、路径的格式、坐标等等,所以这是很有启发意义的:)

我希望这对你有帮助,如果你发现自己在同样的情况!

 类似资料:
  • 我试图构造带有viewBox属性的内联SVG,但没有显式的width或height属性。我正在使用CSS将SVG的宽度设置为100%。这将允许SVG缩放到其包装容器中,保持由ViewBox设置的纵横比。在Chrome和Firefox中,这是完美的! 下面是我所讲内容的一个最小代码示例:http://codepen.io/pcorey/pen/amkgl HTML: CSS: viewBox是100

  • 如何不是用 width 和 height 控制 svg 的渲染大小? 下面的网站 https://nicegui.io/ 首页左上角的的 「NiceGUI」的尺寸不大不小刚刚好,对应的 svg 是:https://github.com/zauberzeug/nicegui/blob/main/website/static/nicegui_word.svg https://nicegui.io/ 这

  • SVG VIEWBOX viewport 首先来了解下SVG中的viewport这个概念,简单来说viewbox就是值指SVG图片本身可视区域的大小,除了SVG本身,其它一些元素也有可视区域的限制,比如symbol、image、pattern等。 在SVG中viewport主要是通过width和height属性来定义的。比如,我们定义一个width="600"和height="600"就表示我们定

  • 描述 (Description) 调整大小操作会将width, height, data-width and data-height属性设置为“img”/“video”或“a”标记。 这样,您的图像将以请求的大小显示。 例子 (Example) ![](video.mp4?resize = 400, 220) 输出 (Output) 上面的代码将生成以下输出&

  • 描述 (Description) cropZoom用于根据请求zoom和crop图像。 宽高比将相同,但图像将被裁剪,生成的图像将设置在center 。 例子 (Example) ![My new image](example-1.jpg?cropZoom = 600, 200) 输出 (Output) 上面的代码给出了以下结果 -

  • 描述 (Description) 使用CropResize ,您可以根据图像的宽度和高度将图像调整为更小或更大的尺寸。 在背景区域中裁剪常规resize 。 例子 (Example) ![My new image](example-1.jpg?cropResize = 300, 300) 输出 (Output) 上面的代码将获取以下输出 -