Image 'contain' resizeMode not working in react native
Asked Answered
B

7

36

I am using React Native on a real Android device. When creating a really simple app with just the following render function on the main app component...

render() {
  <Image
    source={{uri:'http://resizing.flixster.com/DeLpPTAwX3O2LszOpeaMHjbzuAw=/53x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/16/47/11164719_ori.jpg'}}
    style={
      {
        flex: 1,
        resizeMode: 'contain',
        backgroundColor: 'yellow'
      }          
    } />
}

I get the following result on my device: screenshot_2016-04-05-11-05-41

As you can see the whole background is yellow so that tells us the image element is taking the whole screen size indeed. But it is just rendered wrong. The 'cover' resizeMode does work as expected (and so does the 'stretch' mode). It is the 'contain' mode that is not working (the most important one from my point of view). The problem gets even worse when placing the image on a ListView since the image does not even show.

UPDATE 1 As Frederick points out, 'contain' only works when the image is larger than the container size. So how can we make the image take the whole container size while keeping its aspect ratio? Percentages are not supported yet by styles in React, and I don't know how to get the image width and height properties once the image is loaded. None of the events associated with the Image component provide that info.

UPDATE 2 Good news. I am now using React Native v0.24.1 and it seems the image 'contain' mode now works as expected, even when the actual image size is smaller than its container. zvona's solution is good (although you need to bear in mind that onLayout will give you the image view size the image is rendered in, but NOT the actual image size being loaded). As for now, I don't know of any way to find out the actual image size (let's suppose you are retrieving the image from a network resource and you don't know the size, which could be very important if you want to calculate its aspect ratio).

Brinkema answered 5/4, 2016 at 20:57 Comment(0)
B
23

This is the trick:

 render() {
    return (
        <Image
          style={{ flex: 1, height: undefined, width: undefined }}
          source={require("../../resource/image/bg_splash.jpg")}
          resizeMode="contain"
        />

    );
  }
Banjo answered 25/5, 2019 at 7:32 Comment(0)
S
9

This is the latest solution:

Image.resizeMode.contain is not working with latest version of react native so i use it like this:

import ImageResizeMode from 'react-native/Libraries/Image/ImageResizeMode'

<Image source={image} resizeMode={ImageResizeMode.contain} />
Soembawa answered 15/11, 2018 at 6:42 Comment(2)
simply assigning 'resizeMode="contain"' to the Image works for me as well with RN 0.57. the resizeMode style seems to no longer be recognized.Hypnotist
@JoeyT I'm using RN 0.62.2 and the style seems to work for me.Azobenzene
B
7

This is what worked for me with the latest react-native 0.37:

<Image source={require('../images/my-image.png')} resizeMode={Image.resizeMode.center} />

Answering the updated part of the question. You can get the image size for external images using Image.getSize.

For local images, a not so documented way to figure out the size and thereby calculate the aspect ratio is using resolveAssetSource which is a react-native module (no need for an external library):

let resolveAssetSource = require('resolveAssetSource')
let { width, height } = resolveAssetSource(image_source)
let aspectRatio = width / height
Barncard answered 13/11, 2016 at 21:44 Comment(3)
This was it for me, the docs made it seem as if the resizeMode value was set inside the style prop. At least that's the way I read it.Metacarpal
I do set resizeMode in the styles as well and it also worksBarncard
this no longer works for me in react native 0.57 'Image.resizeMode' is undefined.Hypnotist
P
6

My answer to UPDATED part of the question:

<Image source={{uri:'...'}} onLayout={this.onImageLayout} />

where:

onImageLayout: function(data){
  console.log('layout', data.nativeEvent.layout);
}

These should be proportioned to device width + height, which you get with:

const {
  Dimensions,
  .
  .
  .
} = React;

const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;

And if you want to get width/height as percentages in styles, you just define e.g.:

const styles = StyleSheet.create({
  image: {
    width: windowWidth * 0.75,
    height: windowHeight * 0.33
  }          
});
Popgun answered 6/4, 2016 at 8:13 Comment(0)
H
1

"Contain" only resizes your image when the image size is larger than the container you're trying to fit it in. In this case, your container is the full screen. The image you're loading via the URL is way smaller, since it's only 53 by 77 pixels. So it won't resize.

I think "cover" should do what you're trying to achieve. However, due to the size the image, it won't look very nice when it is magnified like that. Made an example here: https://rnplay.org/apps/X5eMEw

Haha answered 5/4, 2016 at 21:13 Comment(2)
Damn! You're totally right! I forgot about that. The problem with React is that you cannot use percentages in width and height style properties... so now I just don't know how to make the image take the whole container size while keeping its aspect ratio!!!Brinkema
Isn't that what "cover" is supposed to do? From the docs: 'cover': 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 larger than the corresponding dimension of the view (minus padding).Haha
M
1

Adding the aspect ratio worked for me:

<Image
  source={item.imageUrl && item.imageUrl != '' ? { uri: item.imageUrl } : require('../../assets/images/no-image-icon-15.png')}
  style={{
      flex: 1,
      aspectRatio: 1.5,
      height: undefined,
      width: undefined
  }}
  resizeMode="contain"
/>
Monarda answered 30/1, 2021 at 16:14 Comment(0)
A
0

I will suggest you a simple solution to apply if it's convenient for you.

use "ImageBackground" component of react-native.

so your code will become something like this:

<ImageBackground
    source={{uri:'http://resizing.flixster.com/DeLpPTAwX3O2LszOpeaMHjbzuAw=/53x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/16/47/11164719_ori.jpg'}}
    style={{flex: 1}} />

In your particular case you are apparently trying to cover whole screen with the image so this solution is exactly for that purpose. However most of the time it works in other cases as well where you want to fit the image properly in its view.

Ariel answered 27/1, 2023 at 12:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.