Maintain aspect ratio of image with full width in React Native

React Native

React Native Problem Overview


I have a query regarding tag. I want an image to take entire width of parent which I do using alignSelf:stretch, but I also want the height to be according to the aspect ratio of the image. How can I achieve something like this?

So I want a way to specify the height as a ratio of the width of the Image.

React Native Solutions


Solution 1 - React Native

Use style={{ aspectRatio: 3/2 }} for a horizontal image with width to height ratio of 3:2.

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

(Available in RN 0.40+)

Solution 2 - React Native

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

});

Solution 3 - React Native

I like bdv's approach and I use this kind of images almost everywhere in my app. That's why I created an own component which is using onLayout to also support device rotation.

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

You can use it like this:

http://example.com/image.jpg" }} />

Or if you know the ratio like this:

http://example.com/image.jpg"}} ratio={0.5} />

Solution 4 - React Native

It's actually pretty simple.

The Image class has a getSize method. [1]

Let's say that you've created a component for your aspectRatioImage and you calculate the appropriate values every time componentWillMount fires.

Then your code would look something like this:

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

So now that the image height and width are saved in your component's state, you can just run

 <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

Solution 5 - React Native

You can calculate the image height based on the width/height ratio.

So if the image originally is 200x100, after setting its resizeMode to stretch:

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

...

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

I know maybe it is not the best practice, but it helped me a lot with images of all sizes that needed to mantain a certain relation with other images, etc.

Solution 6 - React Native

You can use react-native-scalable-image. The following example will do the job:

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

Solution 7 - React Native

Typically, doing the following would give us an image rendered to max width/height depending on orientation while maintaining the aspect ratio of the image itself:

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

Using 'contain' with resizeMode: Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or less than the corresponding dimension of the view (minus padding).

Update: * Unfortunately, it seems that there is a common bug with resizeMode's 'contain' specifically when using react native for Android: https://github.com/facebook/react-native/pull/5738*

Solution 8 - React Native

In my case i also had to set height to 'auto' :

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

Solution 9 - React Native

In my case, I am using Styled Components in my React Native (v0.62+) project.

I needed to specify a square aspectRatio for Image components that had a defined width and undefined height.

I found that styling height:0; achieved the "square image" result that I wanted:

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

This method also works for full width image styling - replacing width:50% with width:100% produces the expect result with correct aspect ratio of each image.

Solution 10 - React Native

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

}

Solution 11 - React Native

With resizeMode='contain' and flex=1 I get the image in full width while keeping the aspect ratio.

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

The image need to be in a container View with flex or height defined, so the flex of the image can work.

Solution 12 - React Native

I tried the Image.getSize approach, but had problems, since we gather all the image links in a config file and then pass the ImageURISource into the source prop of the Image.

My solution for that was to wait for the Image onLayout callback to get it's layout properties and use that to update the dimensions. I created a component for that:

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

This will update the dimensions of the image to match the width of the screen.

Solution 13 - React Native

Use resizeMode='contain'

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

This will keep the original aspect ratio, with given width and height as max-height and max-width.

Solution 14 - React Native

You may use something like this:

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

Please not that you still have to set the height on the view container.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionParam AggarwalView Question on Stackoverflow
Solution 1 - React NativeParam AggarwalView Answer on Stackoverflow
Solution 2 - React NativeStirnerView Answer on Stackoverflow
Solution 3 - React NativetomatentobiView Answer on Stackoverflow
Solution 4 - React NativebdvView Answer on Stackoverflow
Solution 5 - React NativeCamilaView Answer on Stackoverflow
Solution 6 - React NativeIhor BurlachenkoView Answer on Stackoverflow
Solution 7 - React Nativeantihero989View Answer on Stackoverflow
Solution 8 - React NativerenasView Answer on Stackoverflow
Solution 9 - React NativeDacre DennyView Answer on Stackoverflow
Solution 10 - React NativeAkshay KhandarkarView Answer on Stackoverflow
Solution 11 - React NativeB. MohammadView Answer on Stackoverflow
Solution 12 - React NativegtRfnkNView Answer on Stackoverflow
Solution 13 - React NativeSoni KamalView Answer on Stackoverflow
Solution 14 - React NativeLukas ReichartView Answer on Stackoverflow