Reputation: 1350
I have an image I'd like to be full width of the device screen.
Using just a View I can achieve this:
<View style={{flex:1}}>
<Image resizeMode="contain" style={{flex: 1, height: undefined, width: undefined}} source={this.props.images.infoImage} />
</View>
Changing this to a ScrollView causes the image to stop rendering completely:
<ScrollView style={{flex:1}}>
<Image resizeMode="contain" style={{flex: 1, height: undefined, width: undefined}} source={this.props.images.infoImage} />
</ScrollView>
I found that if I set a height on the image it would render...but I want the image to dynamically respond to the size of the device.
How can I solve this without declaring an explicit height?
Upvotes: 0
Views: 4178
Reputation: 1350
As per @martinarroyo's comment I added contentContainerStyle={{flex:1}}
to the ScrollView, like so:
<ScrollView contentContainerStyle={{flex:1}}>
<Image resizeMode="contain" style={{flex: 1, width: undefined, height: undefined}} source={this.props.images.infoImage} />
</ScrollView
This completely resolved my issue. The image is the full width of the display while maintaining the correct aspect ratio.
EDIT: Turns out the image frame height stays the same but the image scales down. This means it has large chunks of padding on the top and bottom. As of now I don't know how to remove it.
EDIT 2:
It seems there aren't any tools out of the box with RN and ultimately ended up using a modified version of @Ihor Burlachenko's solution. I created a custom component that takes desired width/height constraints and scales it based on that. I need to use this for local files, which Image.getSize()
method does not work on, so I modified Ihor's solution to allow for that by passing in a dimensions object that contain width and height.
import React from 'react';
import { Image } from 'react-native';
export default class ScalableImage extends React.Component {
constructor(props) {
super(props);
this.state = {
width: null,
height: null,
}
}
componentDidMount() {
if(typeof this.props.source === 'string') {
Image.getSize(this.props.source, this._calculateImageDimensions, console.log);
} else if(this.props.dimensions) {
this._calculateImageDimensions(this.props.dimensions.width, this.props.dimensions.height)
}
}
render() {
return (
<Image
{ ...this.props }
style={[
this.props.style,
{ width: this.state.width, height: this.state.height }
]}
/>
);
}
_calculateImageDimensions(width, height) {
let ratio;
if (this.props.width && this.props.height) {
ratio = Math.min(this.props.width / width, this.props.height / height);
}
else if (this.props.width) {
ratio = this.props.width / width;
}
else if (this.props.height) {
ratio = this.props.height / height;
}
this.setState({ width: width * ratio, height: height * ratio });
}
}
ScalableImage.propTypes = {
width: React.PropTypes.number,
height: React.PropTypes.number,
dimensions: React.PropTypes.object
};
I then use it as so:
<ScalableImage source={require('../path/to/local/image.png')}
width={Dimensions.get('window').width()}
dimensions={{width: 700, height: 400}} />
Upvotes: 6
Reputation: 4905
I ended up wrapping React Image inside custom Image component which calculates height dynamically to keep the image ratio in onComponentDidMount
:
Image.getSize(this.props.source.uri, (width, height) => {
let ratio;
if (this.props.width && this.props.height) {
ratio = Math.min(this.props.width / width, this.props.height / height);
}
else if (this.props.width) {
ratio = this.props.width / width;
}
else if (this.props.height) {
ratio = this.props.height / height;
}
this.setState({ width: width * ratio, height: height * ratio });
}, console.log);
And then I use it like that:
<Image width={Dimensions.get('window').width} source={{uri: '<image uri>'}} />
Upvotes: 0
Reputation: 9701
As a last resource, you can use Dimensions.
Get the windows's width and height on every render
, that way you'll account for changes in size (basically, rotations) and will match every device.
You can use it like this:
import {Dimensions} from 'react-native'+
// Then, in your component:
render(){
const {width, height} = Dimensions.get('window'):
return (<ScrollView style={{flex:1}}>
<Image resizeMode="contain" style={{flex: 1, height, width}} source={this.props.images.infoImage} />
</ScrollView>)
}
Upvotes: 0