Is there a way how to control image position with resizeMode set to cover? I'm looking for similar result as can be achieve by using background-positon: center bottom in traditional CSS.
Here is an illustration of the situation:
Image with same dimensions as screen
Image with custom height, picture gets centered
(Desired) Image with custom height, but with picture aligned to the bottom edge of the element
My code:
<Image
source={require('./eifell.jpg')}
resizeMode={Image.resizeMode.cover}
style={{
height: 300
}}
/>
I believe you'll have to achieve this by using the transforms prop on the image style and utilize the translateY transformation.
It will involve a little math... off the top of my head I believe you would need to follow these steps:
Use Image.getSize() to find the dimensions of your image
Then based on the size of your window from Dimensions.get('window') calculate how many pixels your image will scale to.
Find the difference between the height displayed (say 667px) and the desired height of the image (300px in your example)
Then translate the image up that many pixels.
Related
I'm trying to build this:
Right now I'm building this by doing all the text in a flex box and having two sibling absolutely positioned boxes with partial borders to make the lines, like this:
<ContainerView>
<TextSection />
<LeftFloat />
<RightFloat />
</View>
This isn't great on different screen sizes, though, because I have to tell those border boxes how to tall and high to be. And the text takes up different heights/widths on different screen sizes so there is no one-size-fits-all value, even when it's a screen percentage, that works for the borders on all devices.
I tried doing something inline like this:
<Text>BECOME A SUBSCRIBER</Text><HorizontalLine />
<VerticalLine /> <BulletView /> <VerticalLine />
<HorizontalLine /><Text>Tap here to learn more ></Text>
but that was worse because the horizontal and vertical lines wouldn't join up nicely to form a corner. I could manipulate them with negative margins but the effect was different between Android and iOS.
Is there a better way to build this kind of border situation?
Or is there a way for these floating boxes to find the width of the "BECOME A SUBSCRIBER" and "Tap here to learn more" elements so they can set their widths accordingly?
The View prop 'onLayout' would be helpful here. You can let the other container expand with flex, and then grab the dimensions of it. Afterwards you could calculate the size you want using screen dimensions and this layout data.
<View onLayout={e => e.nativeEvent.layout}
If you specify dimensions in the style prop of an <Image> component in React Native, adding resizeMode={'contain'} causes the image to preserve its aspect ration and fit entirely in the box whose dimensions you've specified in style. It will also center the image horizontally and vertically within that box.
However, as far as I can tell, center does the same thing as contain. What's the difference?
The difference is how the image fits in the Image container.
Center: the image will be centered in the image container according to the size of the container. It will have uniform space on left, right and top, bottom sides because the image is centered.
Contain: the image is fitted inside the image container keeping the aspect ratio of the image. This means the image will touch the container walls from either width or height or both depending on which side is larger or smaller.
Container is the Image component itself.
In order to see the differences in action, give background color to the Image component.
See the expo slack to better understand it: https://snack.expo.io/#saadqbal/resizemode
From the official document it says:
center:
Center the image in the view along both dimensions. If the
image is larger than the view, scale it down uniformly so that it is
contained in the view.
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).
To get the clear idea about it I would suggest a small trick.
Take a view of 50*50 and put image inside it. Now take rectangle(with more height) and square image. See the difference.
When you use contain it satisfies the following condition
Scale Image Width ≤ Image View Dimension Width
Scale Image Height ≤ Image View Dimension Height
When you use center if image is smaller than the view it will have empty spaces in both x and y directions depending on the image size.
If it is larger then ( unless if you specified the scale ) by default it scales down to contain in it ( this is the situation where it appears to be acting similar to contain )
If the image is larger than the view, scale it down uniformly so that it is contained in the view. Documetation
Check this explanation Understanding “resizeMode” in React Native by Mehran Khan
I have a large image I would like to center in a View. I would like the height of the ImageView to take up 100% of device height, and whatever the width is to take up device width.
I don't want the images squashed to fit the width of the device, I want to see the center of the image and if any width is offscreen and invisible that's perfectly fine.
I've tried a few things but nothing works.
EDIT: My answer below works for iOS, but I still haven't figured out a way to get this to work properly on Android. I used ui.js by FokkeZB:
https://github.com/FokkeZB/UTiL/blob/master/app/lib/ui.js
This does what I want it to do with my image, but it's unfortunately a little slow (image loads after screen appears. I suppose I can load all images upfront and apply them later.
I ended up doing some simple math in this situation. Get height of the device:
var height = Math.floor(Titanium.Platform.displayCaps.platformHeight);
Then I set the height of my imageView to height of device. Next I needed the ratio of my image:
var ratio = imgOgWidth/imgOgHeight
And multiply that by device height:
var imageWidth = height * ratio;
And my xml was set up like this:
<View clipMode="Titanium.UI.iOS.CLIP_MODE_ENABLED" height="Ti.UI.FILL" width="Ti.UI.FILL">
<ImageView id="background_image" image="/images/myImage.jpg"/>
</View>
In my .js file I set my image width and height to the above. Works well! Probably different for landscape but this worked for my app which is locked to portrait.
Note: This is only working for iOS.
I am trying to have an image inside a ScrollView taking the full width of the screen while keeping its aspect ratio (I don't want a fixed background image). The answers in https://github.com/facebook/react-native/issues/950 seem to work for a View but not a ScrollView.
The null width/height trick just makes the image disappear. Setting the width using Dimensions.get('window').width does not work for some reason; it leaves some space either on the top and bottom or the left and right of the image depending on its aspect ratio.
I can't use Image.getSize() as the image is local and would rather avoid hard-coding the dimensions as I have many other images that need to be styled this way. I have tried many other combinations of flex, alignSelf, etc. but none seem to work.
Setting ScrollView's style={{width: "100%"}} works for me.
I have a 405x720 image that it is to cover the background image. I've noticed that it stretches the image if the device's screen is smaller than the image. (I'm using a Galaxy S4 to test my apps).
Here's what I have so far:
var fullView = Ti.UI.createImageView({
layout: 'vertical',
width: '100%',
height: '100%',
image: '/images/background.png'
});
I've heard about the clipping technique, however that is only available for iOS and I'd like to have it for both platforms. Is there a way to do this? Or should I try to resize it appropriately? Tips/Suggestions are appreciated!
You should use proper images according to the aspect ratio of screen you are going to run your app on.
You can do this by calculating the width-height ratio of device and then you can decide which image to show on.
But putting a single resolution image directly to cover up the whole screen
is never going to work.
To resize an image, you can use Ti.Blob class' methods after fetching your image using Ti.Filesystem
Also remember that putting an image on whole background takes lot of memory especially in Android. That's why most of the apps do not use complete image to cover up background, rather they use small images wherever necessary and fills up other areas by colors or gradients as required.
But if your requirement is only to use image in background then unload it as soon as you move to different screen and load it again as you are back on it.
Further points to keep note of:
If you set bg image on a View, then it will be fit to cover the dimension of a View. So, if you have a view of width/height to 100%, then image will be fit into it. It means that image size will depend on View's dimension, not the View dimension will depend on image size.
If you set image on ImageView, and suppose you have:
ImageView width = FILL to screen size of 720, then the image height will be automatically decided to keep the aspect ratio. It means that if you have an image of size width=720 and height=400, then the ImageView will be of width=FILL & height=400
Image of size width=1000 and height=800 & ImageView height = 400, then the ImageView will be of width=500 & height=400
The problem is that you're actually telling the image control to load the image on an object that is stretched to the entire width and height of the screen - and when the screen aspect ratio is different than the one you have cropped your image by then you get bad aspect ratio and image looks screwed up.
If you remove either the width or the height, than the aspect ratio of the image will be loaded.
When I want a background image what I found the best way is to make a square image, and then set my ImageView height to Ti.UI.FILL and my width to Ti.UI.SIZE - That way it shows good aspect ratio and side that dont "fit" the screen (width or height) are not shown.