如何使用 react-native-svg 找到宽度、高度和 viewBox 的正确值 [英] How to find correct values for width, height and viewBox with react-native-svg

查看:162
本文介绍了如何使用 react-native-svg 找到宽度、高度和 viewBox 的正确值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试做一些看起来很简单的事情,但我已经尝试了几个小时,但找不到解决方案.

我有一个需要位于屏幕顶部的 SVG.它来自具有以下尺寸的设计师:

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

React Native 中,这将进入容器内部,而 SVG 需要占据屏幕的整个宽度,我正在从中获取:

Dimensions.get("window").width

我的问题是,我还没有找到一种方法来缩放 SVG 以占据屏幕宽度的 100%,找出正确的高度(或自动设置的方法),并保留纵横比.我已经尝试了一百万种方法,包括使用容器的 aspectRatio 样式和它的 height(或者根本不设置 height).每当我发现一些有效的比例"时,我都会尝试使用不同屏幕宽度的不同设备,但它看起来一点也不好看(裁剪过,小于屏幕宽度等).

我觉得 SVG (react-native-svg) 中的 preserveAspectRatio 属性与 aspectRatio 样式有某种冲突.我对 preserveAspectRatio 完全迷失了,我还没有找到一种方法可以在不裁剪的情况下使其缩放.

有人知道如何实现这一目标吗?

这是我的最终代码,它返回一个显示 SVG 的 HeatMap 组件,但尽管它具有正确的高度,但 SVG 的一部分从右侧超出了屏幕(看起来被裁剪,因为它太宽了):

const windowWidth = Dimensions.get("window").width;const getSVGRootProps = ({ width, height }) =>({宽度:100%",高度:100%",视图框:`0 0 ${width} ${height}`,保留AspectRatio:xMinYMin满足",});const FieldShape = () =>{常量宽度 = 354;//原始宽度常量高度 = 190;//原始高度const aspectRatio = 宽度/高度;//调整高度 = <屏幕宽度>* 原始高度/原始宽度const 计算高度 = (windowWidth * height)/宽度;const 字段样式 = {宽度:窗口宽度,高度:计算高度,纵横比,};返回 (<视图样式={fieldStyles}><Svg {...getSVGRootProps({ windowWidth,calculatedHeight })}>...</Svg></查看>);};const HeatMap = () =>{返回 <FieldShape/>;};

结果如下:

解决方案

我已经找到了解决方案,我将它张贴在这里,以防有人在使用 React Native 和 SVG 时遇到同样的问题.基本上,如果您尝试获取 SVG 文件并将其转换为具有动态"部分的组件(例如根据数据以编程方式将颜色设置为路径,或显示 SVG 文本),您可能会遇到此问题.

我所做的是使用 SVGR 将原始 SVG 转换为 React Native 组件(使用 react-native-svg).然后我只是根据需要用变量(来自道具)替换了硬编码数据.看起来不错,但我对组件的大小有疑问.我找不到在不同设备尺寸和分辨率下显示它的一致方式.这看起来很简单,但我尝试了几个小时,结果在每个屏幕尺寸上都不同.在此处询问并在 react-native-svg repo 上打开一个问题后,我没有得到答案也没有任何线索(不是责怪任何人,只是说这可能不是很多人遇到的问题).于是我挖又挖,终于找到了 Lea Verou 撰写的这篇博文,她在其中讨论了绝对和相对 SVG 路径.这让我想到,也许我在寻找完美的调整大小公式时遇到了很多问题,因为我的路径不是相对的,而是绝对的.所以我尝试了这个 heyzeuss 的 jsfiddle,粘贴我的(原始)SVG 代码,然后复制结果.我将结果粘贴到这个方便的 SVGR playground(SVG 到 JS)工具中,然后我做了一些改动实现我的目标:

  • 我希望我的 SVG 占据全屏的宽度,宽度和高度相应地缩放.

所以这就是我改变的:

//SVG 的原始大小为 519 宽,260 高//<Svg width="519" height="260" viewBox="0 0 519 260">...</Svg>//我还添加了一个容器,它强制执行纵横比const originalWidth = 519;const originalHeight = 260;const aspectRatio = originalWidth/originalHeight;const windowWidth = Dimensions.get("window").width;返回 (<视图样式={{ width: windowWidth, aspectRatio }}><SVG宽度="100%"高度="100%"viewBox={`0 0 ${originalWidth} ${originalHeight}`}>...</Svg></查看>)

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

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

用于将绝对路径转换为相对路径的脚本是该库的一部分,名为 Snap.svg,但你只需要 1% (Snap.path.toRelative).我正在考虑使用一个小工具来获取 svg 文件中的所有路径,并应用此转换.老实说,我多年来一直在处理 SVG 文件,但我从来没有真正了解过它的内部工作方式、路径的格式、坐标等,所以这很有启发性:)

如果您发现自己处于同样的情况,我希望这对您有所帮助!

I have been trying to do something that seemed easy, but I have been trying for a few hours and I can't find the solution.

I have an SVG that needs to be on top of a screen. It came from the designer with these dimensions:

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

In React Native, that would go inside of a container, and the SVG needs to take the full width of the screen, which I am taking from:

Dimensions.get("window").width

My problem is, I haven't found a way to scale the SVG to take 100% of the screen width, finding out the correct height (or a way for it to be set automatically), and preserve the aspect ratio. I've tried like a million things, including playing around with the container's aspectRatio style and its height (or not setting the height at all). Whenever I've found some "proportions" that worked, I tried in a different device with different screen width and it didn't look good at all (cropped, smaller than the screen's width, etc).

I feel like the preserveAspectRatio property in the SVG (react-native-svg) is somehow conflicting with the aspectRatio style. And I am totally lost with the preserveAspectRatio, I haven't found a way to make it scale without being cropped.

Does anyone have any idea how to achieve this?

This is my final code, which returns a HeatMap component showing an SVG, but although it has the correct height, part of the SVG is out of the screen from the right (looks cropped because it's too wide):

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 />;
};

This is the result:

解决方案

I've found the solution, and I am posting it here in case anyone runs into the same problem with react native and SVG. Basically, if you're trying to get an SVG file and turn it into a component with "dynamic" parts (like programmatically set colors to path based on data, or display SVG text), you'll probably run into this issue.

What I did was to use SVGR to convert the original SVG into a react native component (with react-native-svg). Then I just replaced hardcoded data with variables (from props) as needed. It looked good, but I had a problem with the component's size. I couldn't find a consistent way to display it across different device sizes and resolutions. It seemed easy, but I tried for hours and the results were different on each screen size. After asking here and opening an issue on react-native-svg repo, I got no answers and no clues (not blaming anyone, just saying it was maybe not something a lot of people runs into). So I digged and digged and I finally found this post by Lea Verou, where she talked about absolute and relative SVG paths. That made me think that maybe I was having so many issues trying to find the perfect resizing formula because my paths weren't relative, but absolute. So I tried this jsfiddle by heyzeuss, pasting my (original) SVG code, and then copying the results. I pasted the results into this handy SVGR playground (SVG to JS) tool, and then I changed some bits to achieve my goal:

  • I want my SVG to take the full screen's width, width its height scaled accordingly.

So this is what I changed:

// 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>
)

I learned some things while doing this, for example, that there's a @svgr/cli included in create-react-app and also available in my react-native project without installing anything extra, so it must be bundled with the original dependencies too. You can run this command and it'll turn a single file or all files in a folder from .svg to React components:

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

The script used to transform absolute paths to relatives is part of this library called Snap.svg, but you'll only need like a 1% of it (Snap.path.toRelative). I am thinking of having a small tool that would take all the paths in an svg file, and apply this transformation. To be totally honest, I have been dealing with SVG files for years but I never really had a proper look at how it works internally, the format of the paths, coordinates, and so on, so this has been highly instructive :)

I hope this helps you if you find yourself in the same situation!

这篇关于如何使用 react-native-svg 找到宽度、高度和 viewBox 的正确值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆