Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Image Alignment when using resizeMode = contain

Tags:

react-native

I'm using React Native's Image tag to display an image with a variable width and height. I have set the Image to 100x50 and set the resizeMode = contain which works almost perfectly, however if the image is resized, it's coming out completely centered vertically and horizontally. Can this behavior be altered? Mockup screenshot :

enter image description here

The red box indicates the Image element set at 100x50. The laptop pic represents the variable width/height picture. You'll notice that the behavior is pushing everything centered either vertically or horizontally.

In the second example, I would like the picture that takes up 100% of the height and roughly half the width to be pushed to be left aligned. Is this possible?

Thanks!

like image 973
efru Avatar asked Mar 16 '16 07:03

efru


People also ask

What is the use of resizeMode in react-native?

resizeMode ​ contain : Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or less than the corresponding dimension of the view (minus padding). stretch : Scale width and height independently, This may change the aspect ratio of the src.

How do I align an image to the left in react-native?

Regarding the alignment of the image, react-native doesn't really care. Images are placed at the middle of the container. If you want to place the image left-aligned, you'll have to write a small algorithm which compares the actual dimensions of the image and dimensions of the container.

How do I change the width and height of an image in react-native?

So all we need to do is create a View with width: "100%" , then use onLayout to get the width of that view (i.e. the container width), then use that container width to calculate the height of our image appropriately.


3 Answers

All - to possibly save some time in the future, this is a quick and dirty method I came up with to resolve this :

logoSize(width, height) {
  var maxWidth = 110;
  var maxHeight = 30;

  if (width >= height) {
    var ratio = maxWidth / width;
    var h = Math.ceil(ratio * height);

    if (h > maxHeight) {
      // Too tall, resize
      var ratio = maxHeight / height;
      var w = Math.ceil(ratio * width);
      var ret = {
        'width': w,
        'height': maxHeight
      };
    } else {
      var ret = {
        'width': maxWidth,
        'height': h
      };
    }

  } else {
    var ratio = maxHeight / height;
    var w = Math.ceil(ratio * width);

    if (w > maxWidth) {
      var ratio = maxWidth / width;
      var h = Math.ceil(ratio * height);
      var ret = {
        'width': maxWidth,
        'height': h
      };
    } else {
      var ret = {
        'width': w,
        'height': maxHeight
      };
    }
  }

  return ret;
}

This will take a width and height of an image, run through some ratio calculations, and spit out a set of dimensions based on maxWidth and maxHeight vars at the top. You can then take the dimensions the method above gives you and apply it to an Image element e.g. :

var dims = logoSize(244,127);
<Image style={[styles.logo, {width:dims.width, height:dims.height}]} source={{uri:'/path/to/image.png}} />

Since the calculations rounds, you may need to apply the resizeMode:'contain' to the styles.logo in your Stylesheet.

Hope this saves someone some time.

like image 53
efru Avatar answered Nov 04 '22 03:11

efru


I've solved a similar task the following way. First you need to set the initial Image styles:

initialImageStyle : { flex:1, resizeMode:'cover' }

This will render the Image in it's original size that we want to capture in a specific onLayout callback. So the trick is to implement that callback in a following manner:

onLayout (e) {
		
	if (this.state.imageSize) { return }
	
	const { x, y,
		height,
		width }		= e.nativeEvent.layout,
		sizeX 		= width - x,
		sizeY 		= height - y,
		imageWidth 	= (sizeX / sizeY) * IMAGE_HEIGHT

	this.setState ({ imageSize: { height: IMAGE_HEIGHT, width: imageWidth, resizeMode: 'contain', }})
}

where IMAGE_HEIGHT is a constant height of your image container. Now all you have to do is just substitute the initial image styles using the state:

<Image
  style={ this.state.imageSize || styles.initialImageStyle }
  source={ /* your image */ }
  onLayout={ this.onLayout.bind (this) }
/>

That's it. In your case you may also need to wrap an image in an additional View. Hope this will help.

Good luck!

like image 26
takatan Avatar answered Nov 04 '22 02:11

takatan


It is quite possible but don't expect react-native to take care of everything. You may want to write a small algorithm to make this happen. What resizeMode="contain" does is that it checks whether the size of the image is greater/less than the container. If it is greater than the container, it will be resized to fit the container. If it is smaller than the container, it will be rendered as it is.

Regarding the alignment of the image, react-native doesn't really care. Images are placed at the middle of the container. If you want to place the image left-aligned, you'll have to write a small algorithm which compares the actual dimensions of the image and dimensions of the container.

For eg. If the height of the image is greater than the container, set the height of the image equal to the height of the container and calculate the width of the container using "aspect ratio". Read this to get a clear idea of what you'll have to do.

Also, play with position: 'absolute' to better suit your needs. Good luck!

Edit: Sorry for not deriving a ready-made solution for you. You might find the desired algorithm on google though. I just shoved you in the right direction.

like image 1
Mihir Avatar answered Nov 04 '22 01:11

Mihir