在 React Native 中保持全宽图像的纵横比

Maintain aspect ratio of image with full width in React Native

我有一个关于标签的问题。我想要一个图像占据我使用 alignSelf:stretch 所做的父级的整个宽度,但我也希望高度根据图像的纵横比。我怎样才能实现这样的目标?

所以我想要一种方法来指定图像的高度与宽度的比率。

你可以这样使用:

<View style={{height:200}} >
<Image source={require('image!MyImage') style={{ resizeMode:Image.resizeMode.ratio, flex:1 }}} />
</View>

请注意,您仍然需要在视图容器上设置高度。

通常,执行以下操作可为我们提供根据方向渲染到最大 width/height 的图像,同时保持图像本身的纵横比:

render(){
    return(<Image style={{'width': Dimensions.get('window').width, 
                         'height': Dimensions.get('window').height}}
                  resizeMode='contain'
                  source='[URL here]'
           </Image>);
}

将 'contain' 与 resizeMode 结合使用:统一缩放图像(保持图像的纵横比),使图像的两个尺寸(宽度和高度)等于或小于视图的相应尺寸(减去填充)。

更新:* 不幸的是,resizeMode 的 'contain' 似乎存在一个常见错误,特别是在 Android 中使用 React Native 时:https://github.com/facebook/react-native/pull/5738*

您可以根据width/height比例计算图像高度。

因此,如果图像最初是 200x100,将其 resizeMode 设置为拉伸后:

var deviceWidth: Dimensions.get('window').width;

...

myImage {
    width: deviceWidth,
    height: deviceWidth * 0.5
}

我知道这可能不是最佳做法,但它对我处理各种尺寸的图像需要与其他图像保持某种关系等有很大帮助

其实很简单。

Image class 有一个 getSize 方法。 [1]

假设您已经为 aspectRatioImage 创建了一个组件,并且在每次 componentWillMount 触发时计算适当的值。

那么您的代码将如下所示:

componentDidMount() {
    Image.getSize(this.props.source.uri, (srcWidth, srcHeight) => {
      const maxHeight = Dimensions.get('window').height; // or something else
      const maxWidth = Dimensions.get('window').width;

      const ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
      this.setState({ width: srcWidth * ratio, height: srcHeight * ratio });
    }, error => {
      console.log('error:', error);
    });
  }

现在图像的高度和宽度已保存在组件的状态中,您可以 运行

 <Image
   style={{ width: this.state.width, height: this.state.height }}
   source={this.props.source}
   resizeMode="cover"
 />

[1] - https://facebook.github.io/react-native/docs/image.html#getsize

您可以使用 react-native-scalable-image。以下示例将完成这项工作:

import React from 'react';
import { Dimensions } from 'react-native';
import Image from 'react-native-scalable-image';

const image = <Image width={Dimensions.get('window').width} source={{uri: '<image uri>'}} />;

我喜欢 bdv 的方法,我在我的应用程序中几乎所有地方都使用这种图像。这就是为什么我创建了一个自己的组件,它使用 onLayout 来支持设备旋转。

import resolveAssetSource from "resolveAssetSource";
import React, { useCallback, useState } from "react";
import { Image, View } from "react-native";

export default function FullWidthImage(props) {
  const [width, setWidth] = useState(0);
  const [height, setHeight] = useState(0);

  const onLayout = useCallback((event) => {
    const containerWidth = event.nativeEvent.layout.width;

    if (props.ratio) {
      setWidth(containerWidth);
      setHeight(containerWidth * props.ratio);
    } else if (typeof props.source === "number") {
      const source = resolveAssetSource(props.source);

      setWidth(containerWidth);
      setHeight(containerWidth * source.height / source.width);
    } else if (typeof props.source === "object") {
      Image.getSize(props.source.uri, (w, h) => {
        setWidth(containerWidth);
        setHeight(containerWidth * h / w);
      });
    }
  }, [props.ratio, props.source]);

  return (
    <View onLayout={onLayout}>
      <Image
        source={props.source}
        style={{ width, height }} />
    </View>
  );
}

你可以这样使用它:

<FullWidthImage source={{ uri: "http://example.com/image.jpg" }} />
<FullWidthImage source={require("./images/image.jpg")} />

或者如果你知道这样的比率:

<FullWidthImage source={{ uri: "http://example.com/image.jpg"}} ratio={0.5} />
<FullWidthImage source={require("./images/image.jpg")} ratio={0.5} />

我尝试了 Image.getSize 方法,但遇到了问题,因为我们在配置文件中收集了所有图像链接,然后将 ImageURISource 传递到 source prop 中图片。

我的解决方案是等待 Image onLayout 回调获取其布局属性并使用它来更新尺寸。我为此创建了一个组件:

import * as React from 'react';
import { Dimensions, Image, ImageProperties, LayoutChangeEvent, StyleSheet, ViewStyle } from 'react-native';

export interface FullWidthImageState {
  width: number;
  height: number;
  stretched: boolean;
}

export default class FullWidthImage extends React.Component<ImageProperties, FullWidthImageState> {
  constructor(props: ImageProperties) {
    super(props);

    this.state = { width: 100, height: 100, stretched: false };
  }

  render() {
    return <Image {...this.props} style={this.getStyle()} onLayout={this.resizeImage} />;
  }

  private resizeImage = (event: LayoutChangeEvent) => {
    if (!this.state.stretched) {
      const width = Dimensions.get('window').width;
      const height = width * event.nativeEvent.layout.height / event.nativeEvent.layout.width;
      this.setState({ width, height, stretched: true });
    }
  };

  private getStyle = (): ViewStyle => {
    const style = [StyleSheet.flatten(this.props.style)];
    style.push({ width: this.state.width, height: this.state.height });
    return StyleSheet.flatten(style);
  };
}

这将更新图像的尺寸以匹配屏幕的宽度。

对于宽高比为 3:2 的水平图像使用 style={{ aspectRatio: 3/2 }}

文档:https://reactnative.dev/docs/layout-props#aspectratio

(在 RN 0.40+ 中可用)

<Image
   source={require('../../assets/img/headers/image-1.jpg')}
   style={styles.responsiveImage}
 />

const styles = StyleSheet.create({

  responsiveImage: {
    width: '100%',
    // Without height undefined it won't work
    height: undefined,
    // figure out your image aspect ratio
    aspectRatio: 135 / 76,
  },

});

在我的例子中,我还必须将高度设置为 'auto':

{
    width: 200,
    height: 'auto',
    aspectRatio: 16 / 9,
}

使用resizeMode='contain'

<Image style={{height:'100%', width:'100%'}} resizeMode="contain" source={{uri:this.state.imgSource}} />

这将保持原始纵横比,给定宽度和高度为最大高度和最大宽度。

就我而言,我在我的 React Native (v0.62+) 项目中使用 Styled Components

我需要为具有已定义 width 和未定义 height.

Image 组件指定正方形 aspectRatio

我发现样式 height:0; 实现了我想要的“方形图像”结果:

// Gallery container styled-component
const Gallery = styled.View`
  flexDirection:row;
  flexWrap:wrap;
`

// Square half-width image styled-component
const Photo = styled.Image`
  width:50%;
  height:0;
  aspectRatio:1;
`

此方法也适用于全宽图像样式 - 将 width:50% 替换为 width:100% 会生成每个图像具有正确宽高比的预期结果。

const RespImage = ({ offer }) => {

const [height, setHeight] = useState(0);
const [width, setWidth] = useState(0);

    let image_url = `YOUR_IMAGE_URI`;

    Image.getSize(image_url, (srcWidth, srcHeight) => {

        const maxHeight = Dimensions.get('window').height;
        const maxWidth = Dimensions.get('window').width;

        const ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
        setHeight(srcHeight * ratio);
        setWidth(srcWidth * ratio);
    });

    return (
        <View>
            <Image resizeMode={'contain'} style={{ height: height, width: width, marginBottom: 20, resizeMode: "contain" }}
                source={{ uri: image_url }}
            />
        </View>
    )

}

使用 resizeMode='contain'flex=1 我在保持宽高比的同时获得全宽图像。

  <Image
     source={{ uri: 'URI' }}
     resizeMode="contain"
     style={{flex:1}} />

图片需要在定义了伸缩或高度的容器视图中,这样图片的伸缩才能起作用。