Home > database >  React Native Image component with "{width: 100%, height: auto}" gets dislocated when using
React Native Image component with "{width: 100%, height: auto}" gets dislocated when using

Time:12-18

I have an Image component that has width from Dimensions.get('window').width, and height that is calculated using this formula:

{ //not the real code, but it works exactly like this.
  width: Dimensions.get('window').width,
  height: actualImageHeight*(Dimensions.get('window').width/actualImageWidth)
}

It basically closely emulates how width: 100%, height: auto works in css.

and it works well until i added margins to it, which causes the image to get dislocated like this: Dislocated Bear

I have also tried to use PixelRatio.getPixelSizeForLayoutSize(margin*2) to try taking account the margin, which makes the new formula look like this:

{ //not the real code, but it works exactly like this.
  width: Dimensions.get('window').width-PixelRatio.getPixelSizeForLayoutSize(margin*2),
  height: actualImageHeight*((Dimensions.get('window').width-PixelRatio.getPixelSizeForLayoutSize(margin*2))/actualImageWidth)
}

and the result is almost, there, but still slightly dislocated: Slightly Dislocated Bear

Which makes me think that Dimensions isn't a good reference for width.

So how do I emulate width: 100%, height: auto that doesn't use Dimensions?

Is it possible to use width: 100% as a reference to use in the formula?

CodePudding user response:

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

const {width, height} = Dimensions.get('window');
const actualImageHeight = 200;
const actualImageWidth = 300;

const Test = props => {
return (
<SafeAreaView style={{flex: 1}}>
  <View
    style={{
      width: width,
      height: actualImageHeight * (width / actualImageWidth),
      borderRadius: 6,
      borderWidth: 1,
      borderColor: '#f1f1f1',
      overflow: 'hidden',
      backgroundColor: 'red',
      padding: 12,
    }}>
    <Image
      style={{flex: 1, width: null, height: null}}
      source={{uri: 'https://picsum.photos/200/300'}}
    />
  </View>
</SafeAreaView>
 );
};

when you place calculated width and height to any view if you place margin in styles it will dislocated the view because while rendering the view margin also considered. Better to wrap image with view.

CodePudding user response:

I still continued the idea of subtracting the width with the margins, and I managed to make it work. Simply by doing Dimensions.get('window').width-(margin*2) will make it work. So final code is:

{
  width: Dimensions.get('window').width-(margin*2),
  height: actualImageHeight*(Dimensions.get('window').width-(margin*2)/actualImageWidth)
}

The result: Bears

Full code of the component:

import React, { useState, useEffect } from "react";
import { Dimensions, Image } from "react-native";

interface AnotherCardProps {
  thumbnail: string;
  margin?: number;
  column?: number;
  maxHeight?: number;
  minHeight?: number;
}

const AnotherCard: React.FC<AnotherCardProps> = (props) => {
  const [imageSize, setImageSize] = useState({ width: 0, height: 0, ratio: 0 });
  const margin = props.margin || 0;
  const column = props.column || 1;
  const newWidth = Dimensions.get("window").width / column - margin * 2;
  const maxHeight = props.maxHeight || newWidth * 1.5;
  const minHeight = props.minHeight || newWidth;

  useEffect(() => {
    Image.getSize(props.thumbnail, (w, h) =>
      setImageSize({
        width: w,
        height: h,
        ratio: newWidth / w,
      })
    );
  });

  return (
    <Image
      style={{
        borderRadius: 20,
        margin: margin,
        flex: 1,
        width: newWidth,
        height:
          imageSize.height * imageSize.ratio < minHeight
            ? minHeight
            : imageSize.height * imageSize.ratio > maxHeight
            ? maxHeight
            : imageSize.height * imageSize.ratio,
        resizeMode: "cover",
      }}
      source={{
        uri: props.thumbnail,
      }}
    />
  );
};

export default AnotherCard;
  • Related