React Native ImageBackground Orientation Change

1.9k views Asked by At

Even though I can get a screen orientation change to update state and re-render, the ImageBackground component still will not update its width.

I have the following code:

<View
  onLayout={event => this.mylayoutchange(event)}
  style={{ flex: 1, backgroundColor: 'green' }}
>
  <ImageBackground
    style={{ flex: 1, width: this.state.width, height: this.state.height }}
    imageStyle={{ resizeMode: 'repeat' }}
    source={require('../assets/images/my_background.jpg')}
  >
    <View>
      <Text>.... Other code here....</Text>
    </View>
  </ImageBackground>
</View>;

When the user changes the orientation of the device the mylayoutchange() function gets called. It updates state correctly. The render function will update. Width and height are correctly changed as can be seen in console.log(). However, for whatever reason, the <ImageBackground> does not update its correct width and height.

When the screen is rotated, the background image no longer fills the entire size of the screen and I instead see the green background color.

What am I doing wrong?

My environment:

"react": "16.13.1",
"react-native": "0.63.2",
3

There are 3 answers

6
Christos Lytras On BEST ANSWER

You need to use resize for resizeMethod in order for the image to get actual resize:

resizeMethod

The mechanism that should be used to resize the image when the image's dimensions differ from the image view's dimensions. Defaults to auto.

  • auto: Use heuristics to pick between resize and scale.

  • resize: A software operation which changes the encoded image in memory before it gets decoded. This should be used instead of scale when the image is much larger than the view.

  • scale: The image gets drawn downscaled or upscaled. Compared to resize, scale is faster (usually hardware accelerated) and produces higher quality images. This should be used if the image is smaller than the view. It should also be used if the image is slightly bigger than the view.

It's obvious that RN picks scale in your case, thus you have to explicitly set it to resize for it to work when the orientation changes and flex style change kicks in:

return (
  <View
    style={{ flex: 1, backgroundColor: 'blue' }}
  >
    <ImageBackground
      // All props other than children, style, imageStyle, imageRef,
      // will be passed to the inner Image component,
      // so, we can use resizeMethod that will be passed to the Image component

      resizeMethod="resize"

      style={{
        flex: 1,
        borderWidth: 1,
        borderColor: 'red'
      }}
      imageStyle={{
        resizeMode: 'repeat',
      }}
      source={require('../assets/images/my_background.jpg')}
    >
      <View>
        <Text style={{
          backgroundColor: 'white'
        }}>.... Other code here....</Text>
      </View>
      <View style={{
        position: 'absolute',
        right: 0,
        bottom: 0
      }}>
        <Text style={{
          backgroundColor: 'white'
        }}>Absolute bottom-right text</Text>
      </View>
    </ImageBackground>
  </View>
);

Result screen capture:

Screen capture

Tested with Environment:

"react": "16.13.1",
"react-native": "0.63.2",

Sample tile image used for repeat background (400 X 400 pixels):

Background tile repeat image

Expo Snack:

RN ImageBackground Orientation Change

2
Oussama Bouthouri On

You can specify the width and height automatically using just CSS, this will ensure that your View takes the full width/height for every size/layout.

     <View
        onLayout={(event) => this.mylayoutchange(event)}
        style={{flex: 1, backgroundColor: 'green'}}>
        <ImageBackground
          style={{
            flex: 1,
            width: '100%',
            height: '100%',
          }}
          imageStyle={{resizeMode: 'repeat'}}
          source={require('../assets/images/my_background.jpg')}>
          <View>
            <Text>.... Other code here....</Text>
          </View>
        </ImageBackground>
      </View>

Considerations:

  • There's a bug in react native that may still exist in your RN version you can take a look to the issue
  • If you still need to specify the width and height using this.state.width and this.state.height consider using usewindowdimensions it is more suitable because it updates automatically.
1
EmpireJones On

I just ran into a similar issue. One workaround that I found is to generate a unique ID (UUID) on each orientation change, and use that UUID as a key for the ImageBackground. This will remount the image and work around the bug.