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


72

我有一个关于标签的查询。我希望图像占据我使用alignSelf:stretch所做的父对象的整个宽度,但是我也希望高度根据图像的长宽比而定。我怎样才能实现这样的目标?

因此,我想要一种将高度指定为图像宽度的比例的方法。


3
这里仍然没有好的答案!
Matt The Ninja

发现这个回购,做了很好的工作。
Marc_Alx

Answers:



58
<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,
  },

});

1
这个答案打开了我的视野,解决了我的问题。但是,出现一个问题,为什么height需要undefined它才能起作用?例如height: X,如果我们使用省略width,它似乎不需要即可工作width: undefined
guiccbr

5
height:undefined是最好的秘密。我的意思不是很好。
isick

3
感谢您提示“ aspectRatio”,但我不需要“ height:undefined”才能使它起作用-也许更新已解决此问题?
penguinflip

想知道这是否是React Native的错误吗?
NikolaMihajlović,

31

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

import resolveAssetSource from 'resolveAssetSource';
import React, {Component} from 'react';
import {Image, View} from 'react-native';

export default class FullWidthImage extends Component {
    constructor() {
        super();

        this.state = {
            width: 0,
            height: 0
        };
    }

    _onLayout(event) {
        const containerWidth = event.nativeEvent.layout.width;

        if (this.props.ratio) {
            this.setState({
                width: containerWidth,
                height: containerWidth * this.props.ratio
            });
        } else if (typeof this.props.source === 'number') {
            const source = resolveAssetSource(this.props.source);

            this.setState({
                width: containerWidth,
                height: containerWidth * source.height / source.width
            });
        } else if (typeof this.props.source === 'object') {
            Image.getSize(this.props.source.uri, (width, height) => {
                this.setState({
                    width: containerWidth,
                    height: containerWidth * height / width
                });
            });
        }
    }

    render() {
        return (
            <View onLayout={this._onLayout.bind(this)}>
                <Image
                    source={this.props.source}
                    style={{
                        width: this.state.width,
                        height: this.state.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} />

感谢使其易于复制/粘贴组件😋
切赫皮勒

3
如果图像源需要是静态图像资源(使用requirelike)require('../../some.png')怎么办?
暂停

自几个月以来,我一直在使用这种方法。这可以正常工作,但是会减慢图像的渲染速度。与采用硬编码宽度-高度的图像渲染(使用2G网络/慢速网络进行测试以获得更大的差异)相比,使用这种方法进行图像渲染所花费的时间(几乎是两倍)。需要最佳解决方案。
Kalpesh Wadekar

@KalpeshWadekar我ratio向组件添加了一个属性。这应该可以解决您的问题。
tomatentobi

1
@Halt您可以使用Image.resolveAssetSource(this.props.source)。参考:stackoverflow.com/questions/41997611/...
古托Marrara马扎冈

13

实际上很简单。

Image类有一个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


我编辑了您的信息,以便删除我的否决票。我不认为图像尺寸是否正确(仍然不确定),但是看到文档建议使用这种方法。
马特·帕里利亚

@MattParrilla它在某种程度上取决于您将使用它的目的。我可以想像您要使用它来“缩放”图像,直到它到达屏幕上某个范围。在这种情况下,状态会很好。如果要显示静态图像,那么将其作为道具传递会更有意义。
bdv

如果图像仍在屏幕上,则此方法效果很好。我遇到了图像getSize仍在处理中,用户交换到其他屏幕,setState现在设置为未安装组件的值的问题。我希望Image组件本身可以采用一种更清洁的方法来根据父组件的宽度缩放高度。上面的解决方案对于固定图像位置非常有效。当我们在FlatList中动态调整图像大小时,它会引起很多警告,其中组件卸载了屏幕上没有的任何项以减少内存占用
samw2k00

5

您可以根据宽度/高度比计算图像高度。

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

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

...

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

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


4

通常,执行以下操作将使我们根据方向将图像渲染为最大宽度/高度,同时保持图像本身的纵横比:

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

在resizeMode中使用“包含”:统一缩放图像(保持图像的长宽比),以便图像的两个尺寸(宽度和高度)都等于或小于视图的相应尺寸(减去填充)。

更新:*不幸的是,似乎有一个resizeMode的“包含”常见错误,特别是在使用Android的本机响应时:https : //github.com/facebook/react-native/pull/5738 *


这样在图像的上方和下方会产生一吨空白吗?(在iOS上)
Matt The Ninja

1
上面的解决方案只是试图使图像适合整个屏幕,而这并不是问题的全部。问题与如何将具有与原始图像相同的长宽比的图像调整为给定宽度有关
samw2k00


3

就我而言,我还必须将高度设置为'auto':

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

0

我尝试了Image.getSize方法,但是遇到了问题,因为我们将所有图像链接收集到一个配置文件中,然后将ImageURISource传递到Image的源属性中。

我的解决方案是等待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);
  };
}

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


0

就我而言,我在我的React Native(v0.62 +)项目中使用样式化组件

我需要指定一个方形aspectRatioImage有一个定义的组件width和不确定height

我发现样式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%会产生具有正确图像长宽比的预期结果。


0

如果要使用maxWidth:

      <View style={{maxWidth:300}}>
      <Image
        source={logo}
        style={{
          width:"100%",
          resizeMode:"contain",
          height: undefined,
          // maxWidth:200,
          aspectRatio: 16 / 9,
        }} />
      </View>

谢谢@Hoenoe


-2

采用 resizeMode='contain'

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

在给定的宽度和高度为max-height和max-width的情况下,这将保持原始的宽高比。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.