39

I have an image that I pull down from a URL. I do not know the dimensions of this image ahead of time.

How do I style / layout the image so that it is the full width of the parent view and the height is calculated so that the aspect ratio is maintained?

I have tried using onLoad in 0.34.0-rc.0 and the height / width are both 0 in event.nativeEvent.source.

The image is in a <ScrollView/>. I am not after a full screen image.

7
  • 1
    resizeMode: 'cover' or 'contain'? Commented Sep 14, 2016 at 18:39
  • I've not been able to use 'cover' or 'contain' without a height set. Any ideas? Commented Sep 14, 2016 at 18:39
  • ahh there's this weird thing with setting them to null and using flex... I think you'll find your answer here somewhere: stackoverflow.com/questions/29322973/… Commented Sep 14, 2016 at 18:41
  • I don't think that works if its in a scroll view. I'm not after a full screen image. Commented Sep 14, 2016 at 18:45
  • github.com/ihor/react-native-scalable-image Commented Feb 23, 2017 at 23:53

9 Answers 9

37

My use was very similar in that I needed to display an image with full screen width but maintaining its aspect ratio.

Based on @JasonGaare's answer to use Image.getSize(), I came up with the following implementation:

class PostItem extends React.Component {

  state = {
    imgWidth: 0,
    imgHeight: 0,
  }

  componentDidMount() {

    Image.getSize(this.props.imageUrl, (width, height) => {
      // calculate image width and height 
      const screenWidth = Dimensions.get('window').width
      const scaleFactor = width / screenWidth
      const imageHeight = height / scaleFactor
      this.setState({imgWidth: screenWidth, imgHeight: imageHeight})
    })
  }

  render() {

    const {imgWidth, imgHeight} = this.state

    return (
      <View>
        <Image
          style={{width: imgWidth, height: imgHeight}}
          source={{uri: this.props.imageUrl}}
        />
        <Text style={styles.title}>
          {this.props.description}
        </Text>
      </View>
    )
  }
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the code! I have been using the component react-native-fit-image but has a lot of problems loading images, sometimes fails to render The unique modification I did to your code is the style of the Image is <Image style={{width: imgWidth, height: imgHeight}} source={{uri: this.props.imageUrl}} />
Where do I mention the actual url for the image?
'Dimensions' is not defined.
@PhilippLudwig import { Dimensions } from 'react-native';
26

I am new on react-native but I came across this solution using a simple style:

imageStyle: {
  height: 300,
  flex: 1,
  width: null}

Image full width from my 1º App:
Image full width from my 1º App

It worked for me.

2 Comments

This does seem to work actually. PS: I had to remove my resizeMode="contain".
How does that answer the original question? You have to know the height of the image ahead...
8

React Native has a function built in that will return the width and height of an image: Image.getSize(). Check out the documentation here

Comments

7

It worked for me.

import React from 'react'
import { View, Text, Image } from 'react-native'

class Test extends React.Component {
  render() {
    return (
      <View>
        <Image
          source={{ uri: "https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQL6goeE1IdiDqIUXUzhzeijVV90TDQpigOkiJGhzaJRbdecSEf" }}
          style={{ height: 200, left: 0, right: 0 }}
          resizeMode="contain"
        />
        <Text style={{ textAlign: "center" }}>Papaya</Text>
      </View>
    );
  }
}

export default Test;

Another way you can get width of parent view after layout event.

<View 
  style={{ flex: 1}} 
  layout={(event) => { this.setState({ width: event.nativeEvent.layout.width }); }}
/>

When you get width parent view from layout event then you can assign width to Image tag.

import React from 'react';
import { View, Image } from 'react-native';

class Card extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      height: 300,
      width: 0
    };
  }
  render() {
    return (
      <View style={{
        flex: 1,
        flexDirection: 'row'
      }}>
        <View style={{ width: 50, backgroundColor: '#f00' }} />
        <View
          style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#fafafa' }}
          onLayout={(event) => { this.setState({ width: event.nativeEvent.layout.width }); }}
        >
          {
            this.state.width === 0 ? null : (
              <Image
                source={{ uri: "https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQL6goeE1IdiDqIUXUzhzeijVV90TDQpigOkiJGhzaJRbdecSEf" }}
                style={{ width: this.state.width, height: this.state.height }}
                resizeMode="contain"
              />
            )
          }
        </View>
      </View>
    );
  }
}
export default Card;

Comments

2

if you have a static image you can use like this

import React, { Component } from "react";
import { View, Animated, Image, Dimensions } from "react-native";
import splashScreen from "../../../assets/imgs/splash-screen.png";

export default class MasterPage extends Component {
  constructor(props) {
    super(props);
    this.state = {
      fadeAnim: new Animated.Value(0),
      imgWidth: 0,
      imgHeight: 0
    };
  }
  checkLogIn = async () => {
    const width = 533; // set your local image with
    const height = 527; // set your local image height 
    // calculate image width and height
    const screenWidth = Dimensions.get("window").width;
    const scaleFactor = width / screenWidth;
    const imageHeight = height / scaleFactor;
    this.setState({ imgWidth: screenWidth, imgHeight: imageHeight });
  };

  async componentDidMount() {
    Animated.timing(
      // Animate over time
      this.state.fadeAnim, // The animated value to drive
      {
        toValue: 1, // Animate to opacity: 1 (opaque)
        duration: 800, // Make it take a while
        useNativeDriver: true
      }
    ).start(this.checkLogIn);
  }

  render() {
    const { imgWidth, imgHeight, fadeAnim } = this.state;
    return (
      <Animated.View
        style={{
          opacity: fadeAnim,
          backgroundColor: "#ebebeb",
          flex: 1,
          justifyContent: "center",
          alignItems: "center"
        }}
      >
        <View>
          <Image
            source={splashScreen}
            style={{ width: imgWidth, height: imgHeight }}
          />
        </View>
      </Animated.View>
    );
  }
}

Comments

2

in my case it works for me changing the aspect ratio and the flex of the image like this

flex:1,aspectRatio:1.2, height:null

Comments

0

try this: pass image uri and parentWidth (can be const { width } = Dimensions.get("window");) and voila... you have height auto calculated based on width and aspect ratio

import React, {Component} from 'react';
import FastImage from 'react-native-fast-image';

interface Props {
  uri: string;
  parentWidth: number;
}

interface State {
  calcImgHeight: number;
  width: number
  aspectRatio: number
}

export default class CustomFastImage extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      calcImgHeight: 0,
      width: props.parentWidth,
      aspectRatio: 1
    };
  }
  componentDidUpdate(prevProps: Props){
    const { aspectRatio, width }= this.state
    const { parentWidth} = this.props
   
    if( prevProps.parentWidth !== this.props.parentWidth){
        this.setState({
            calcImgHeight: aspectRatio * parentWidth,
            width: parentWidth
          })
    }
  }
  render() {
    const {calcImgHeight, width} = this.state;
    const {uri} = this.props;
    return (
      <FastImage
        style={{width: width, height: calcImgHeight}}
        source={{
          uri,
        }}
        resizeMode={FastImage.resizeMode.contain}
        onLoad={(evt) =>
          {
              this.setState({
            calcImgHeight: (evt.nativeEvent.height / evt.nativeEvent.width) * width, // By this, you keep the image ratio
            aspectRatio:  (evt.nativeEvent.height / evt.nativeEvent.width), 
          })}
        }
      />
    );
  }
}

Comments

0

This should work.

imageStyle: {
  resizeMode: 'contain',
}

Comments

-5

incase you can't solve it yet, React Native v.0.42.0 have resizeMode

<Image style={styles.intro_img} source={require('img.png')} 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.