如何在React Native View中自动缩放SVG元素?

ipm*_*mcc 9 react-native

我试图将一个react-native-svg元素放置在View这样的一个元素中,使其以一定的固定纵横比进行渲染,然后在包含视图的范围内将其缩放为尽可能大。

Svg(从元素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"}}/>
Run Code Online (Sandbox Code Playgroud)

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

这就是我所看到的

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

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

<Svg.Svg width="100%" height="100%">
Run Code Online (Sandbox Code Playgroud)

但是,SVG部分根本无法绘制。像这样:

没有SVG渲染

控制台日志中没有错误消息,也没有其他指示为什么不起作用。

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

所需的输出看起来像这样(通过硬编码值获得):

期望的输出

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

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

Aba*_*ous 16

诀窍

  preserveAspectRatio="xMinYMin slice"

Run Code Online (Sandbox Code Playgroud)

你应该这样做

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


Run Code Online (Sandbox Code Playgroud)


Ell*_*ske 7

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

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>
  );
Run Code Online (Sandbox Code Playgroud)

在上下文中:

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>
);
Run Code Online (Sandbox Code Playgroud)

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

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

确保设置aspectRatioviewbox.width / viewbox.height


小智 5

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

请查看本教程,其中对这些概念的解释非常清楚。

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


小智 5

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

对我来说解决这个问题的方法是确保您不会弄乱viewBox中的或给定的值Paths(就像我所做的那样),而只更改heightwidth来填充,然后像其他答案一样使用容器:

<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>
Run Code Online (Sandbox Code Playgroud)