36

我试图将一个react-native-svg元素放入其中View,使其以特定的固定纵横比呈现,然后在包含视图的范围内尽可能大地缩放。

Svg元素 (from )react-native-svg似乎只接受绝对值widthheight属性(我尝试使用百分比,但没有渲染,并且调试确认百分比值是NSNull在它们到达本机视图时)。我不确定如何达到预期的效果。这是我到目前为止所尝试的:

// I have a component defined like this:
export default class MySvgCircle extends React.Component {
    render() {
        return (
            <View style={[this.props.style, {alignItems: 'center', justifyContent: 'center'}]} ref="containingView">
                <View style={{flex: 1, justifyContent: 'center', alignItems: 'center', aspectRatio: 1.0}}>
                    <Svg.Svg width="100" height="100">
                        <Svg.Circle cx="50" cy="50" r="40" stroke="blue" strokeWidth="1.0" fill="transparent" />
                        <Svg.Circle cx="50" cy="50" r="37" stroke="red" strokeWidth="6.0" fill="transparent" />
                    </Svg.Svg>
                </View>
            </View>
        );
    }
}

// And then consumed like this:
<MySvgCircle style={{height: 200, width: 200, backgroundColor: "powderblue"}}/>

这就是我在渲染时看到的。

这就是我所看到的

我希望放大红色和蓝色圆圈以填充 200x200 区域(如果包含视图是矩形而不是正方形,则保持圆形),而无需预先知道组件的消费者/用户所需的大小。

如前所述,我尝试使用百分比,如下所示(其余部分相同):

<Svg.Svg width="100%" height="100%">

但是 SVG 部分根本不绘制。像这样:

没有 SVG 渲染

控制台日志中没有错误消息或其他说明为什么这不起作用。

在 RN 中布局后测量 UI 元素的方法似乎是异步的,这似乎与我正在尝试做的事情不匹配。我可以使用某种缩放或变换魔法吗?

所需的输出将如下所示(通过硬编码值获得):

期望的输出

当包含视图不是一个完美的正方形时,我希望它像这样工作:

水平矩形行为 垂直矩形行为

4

4 回答 4

37

这是一个行为类似于您的图像的组件:

import React from 'react';
import { View } from 'react-native';

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

const WrappedSvg = () =>
  (
    <View style={{ aspectRatio: 1, backgroundColor: 'blue' }}>
      <Svg height="100%" width="100%" viewBox="0 0 100 100">
        <Circle r="50" cx="50" cy="50" fill="red" />
      </Svg>
    </View>
  );

在上下文中:

const WrappedSvgTest = () => (
  <View>
    <View style={{
      width: '100%',
      height: 140,
      alignItems: 'center',
      backgroundColor: '#eeeeee'
    }}
    >
      <WrappedSvg />
    </View>

    {/* spacer */}
    <View style={{ height: 100 }} />

    <View style={{
      width: 120,
      height: 280,
      justifyContent: 'space-around',
      backgroundColor: '#eeeeee'
    }}
    >
      <WrappedSvg />
    </View>
  </View>
);

诀窍是将 SVG 元素包装在保留其纵横比的视图中,然后将 SVG 大小设置为 100% 的宽度和高度。

我相信 SVG 元素大小和视图框大小之间存在一些复杂的交互,这使得 SVG 渲染比您预期的要小,或者在某些情况下根本不渲染。您可以通过将<View>标签保持在固定的纵横比并将<Svg>标签设置为 100% 的宽度和高度来避免这种情况,因此视图框的纵横比始终与元素比率相匹配。

请务必设置aspectRatioviewbox.width / viewbox.height.

于 2019-03-28T23:15:17.133 回答
25

诀窍

  preserveAspectRatio="xMinYMin slice"

你应该这样做

<Svg 
 height="100%" 
 preserveAspectRatio="xMinYMin slice" 
 width="100%" 
 viewBox="0 0 100 100"
>


于 2019-10-15T05:04:36.220 回答
4

您必须与 viewBox 一起使用宽度和高度。通常,您必须在 viewBox 中放置所需形状的原始尺寸。通过根据您的需要定义宽度/高度,您的形状将适当地缩小/放大。

请查看本教程,其中已经非常清楚地解释了这些概念。

https://www.sarasoueidan.com/blog/svg-coordinate-systems/

于 2018-05-15T09:30:01.770 回答
2

对于我的 SVG,我使用的是https://material.io/resources/icons提供的那些

为我解决的问题是确保您不会弄乱 theviewBox或给定的值Paths(就像我所做的那样),而只需更改heightandwidth来填充,然后像其他答案一样使用容器:

<View style={{
    height: 100, display: 'flex',
}}>
    <TouchableOpacity style={{
        display: 'flex', justifyContent: 'center',
        alignItems: 'center', aspectRatio: 1,
    }}>
        <Svg fill="white" height="100%"
             width="100%" viewBox="0 0 24 24">
            <Path d="M0 0h24v24H0z" fill="none"/>
            <Path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
        </Svg>
    </TouchableOpacity>
</View>
于 2020-07-30T16:03:26.323 回答