Maintain aspect ratio of image with full width in React Native
Solution 1:
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:
<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:
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, {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>
);
}
}
You can use it like this:
<FullWidthImage source={{uri: 'http://example.com/image.jpg'}} />
<FullWidthImage source={require('./images/image.jpg')} />
Or if you know the ratio like this:
<FullWidthImage source={{uri: 'http://example.com/image.jpg'}} ratio={0.5} />
<FullWidthImage source={require('./images/image.jpg')} ratio={0.5} />
Solution 4:
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