How can I get the image width to fill the card and the height to be flexible? - react-native

I'm trying to set the dimensions of the image so that the width will always take up the full width of the card (minus the horizontal margin) and with a flexible height, so that it can scale as it needs to.
How can I do this? It seems that the style needs a height, it won't accept null.
I have tried a LOT of combinations using various resizeModes, heights, widths etc.
Here is the component:
And here is my current code:
renderImage(image) {
const { width, height } = Dimensions.get('window');
if (image) {
return (
<View style={styles.imageContainer}>
<Image
style={{ width, resizeMode: 'contain', height: 300 }}
source={{ uri: image }}
/>
</View>
);
}
}

The aspectRatio property solves this problem nicely.
<Image
style={{ width: '100%', aspectRatio: 1 }}
source={{uri: 'https://online.picture/dynamic_size'}}/>

I had same problem for images from web (where no exact width & height was known) and created react-native-web-image. Currently not for local images, only for remote. Try it, I will be glad if it will help.

Set the width to be the screen width, and set height to be undefined.

Related

React Native using Animated to hide Header (leaves blank space after TransformY)

I have implemented hiding header while scrolling in React native using Animated.
Here is the code:
const y = new Animated.Value(0);
const AnimatedWebView = Animated.createAnimatedComponent(WebView);
const HEADER_HEIGHT = 60;
const {diffClamp} = Animated;
function WebPage({route}) {
const diffClampY = diffClamp(y, 0, HEADER_HEIGHT);
const translateY = diffClampY.interpolate({
inputRange: [0, HEADER_HEIGHT],
outputRange: [0, -HEADER_HEIGHT],
});
return (
<SafeAreaView style={{flex: 1}}>
<Animated.View
style={{
height: HEADER_HEIGHT,
width: '100%',
position: 'absolute',
top: 0,
left: 0,
right: 0,
zIndex: 2,
backgroundColor: 'lightblue',
transform: [{translateY: translateY}],
}}
/>
<AnimatedWebView
source={{
uri: 'https://www.stackoverflow.com',
}}
originWhitelist={['*']}
containerStyle={{paddingTop: 60}}
bounces={false}
onScroll={Animated.event([{nativeEvent: {contentOffset: {y: y}}}])}
/>
</SafeAreaView>
);
}
Since Header is positioned absolute to stick to the top, I have given paddingTop(same as height of the header) to avoid header overlapping the contents of the WebView initially. Now because of this, when I scroll, as header disappears, it leaves blank space as shown:
Above is image before & after hiding the Header. Blank space is left where header is used to be. How should I dynamically change the padding so that as header disappears, there is no blank space left? I have tried without absolutely positioning the header and giving no paddingTop to the Webview, but still blank space.
Any help appreciated! Thanks
When you using translateY, it means you're moving your header away from its current position, not the place it holds. And the blank space you saw is kind of an anchor of the header (open your debugger, you will see your header component is just still in old position). In order to move your webview, just bind your webview's translateY along with your header, and you will have perfect animation.
<AnimatedWebView
source={{
uri: 'https://www.stackoverflow.com',
}}
originWhitelist={['*']}
containerStyle={{paddingTop: 60}}
bounces={false}
onScroll={Animated.event([{nativeEvent: {contentOffset: {y: y}}}])}
style={{
transform: [{translateY: translateY}]
}}
/>
Edit 1
I'm thinking of 3 solutions:
You will change the height of the webview along with its position. Check this out: Increase width height of view using animation.
Make your webview's height greater than its default height. So when you translate the webview, the redundant space will cover your blank space. In this case, you have to calculate the height of your webview using React Native Dimension
There is a transform's property, called scale. You can use it to stretch your webview, but I don't know if it will stretch your webview's content or not.

Get coordinates of touch event relative to Image

I have an image centered on the screen. I need to make it touchable and I need to get the coordinates of the touch event relative to the image. I have wrapped my image in a TouchableOpacity to make it touchable. The problem is that the touch coordinates are relative to the TouchableOpacity and not the Image. The TouchableOpacity is taking up the entire screen but the Image is centered inside it.
I either need to make my TouchableOpacity the same size as the Image, or I need to know the offset of the Image within the TouchableOpacity.
I have tried using OnLayout and the NativeEvent object to get the position of the Image within it's parent but it just returns 0,0.
const {width, height} = Dimensions.get("window");
class Inspection extends React.Component {
handlePress(evt) {
// do stuff
...
}
render() {
return (
<View style={{flex:1, backgroundColor:'#fff'}}>
<TouchableOpacity
onPress={(evt) => this.handlePress(evt)}
style={{backgroundColor: '#3897f0'}}
>
<Image
onLayout={({nativeEvent}) => {
console.log(nativeEvent.layout);
}}
source={require('../../images/wireframe-car.jpg')}
resizeMode='contain'
style={{
maxHeight: height,
maxWidth: width
}}
/>
</TouchableOpacity>
</View>
);
}
}
Console Output:
{height: 683.4285888671875, width: 411.4285583496094, y: 0, x: 0}
I've added a backgroundColor to TouchableOpacity so you can see that it takes up the entire screen.
Is there another way of doing this?
TouchableOpacity would be the same size as of the Image because you haven't given any height to it, you simply need to assign onLayout prop to your TouchableOpacity like this
<View
style={{ flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center' }}>
<TouchableOpacity
onLayout={({ nativeEvent }) => {
console.log(nativeEvent.layout)
}}
style={{}}
onPress={evt => this.handlePress(evt)}>
<Image
source={require('../../images/wireframe-car.jpg')}
resizeMode="contain"
style={{
maxWidth: '100%',
}}
/>
</TouchableOpacity>
</View>
This will give you the exact x and y of Image.
Update
The problem is also with image size, since the image size is quite big so it takes the height of the device and we get x:0 and y:0, in order to resolve this issue we can give the Image component a static height or calculate its height according to width. We can get width and height image from local path like this:
let imageUri = Image.resolveAssetSource(require('../../images/wireframe-car.jpg').uri)
Image.getSize(imageUri , (width, height) => {
console.log(`The image dimensions are ${width}x${height}`);
}, (error) => {
console.error(`Couldn't get the image size: ${error.message}`);
});

Image Resize Cover - Keep Top Left of Image

I have a big image that needs to be cropped on certain devices, but it's very important that the top left of my image stays in tact because it has some important content.
<View style={{flex:1}}>
<Image source={MY_IMAGE}
resizeMode="cover"
style={{
flex: 1.8,
width: null,
height: null
}}
/>
<View style={{ flex: 1 }}>
//other content
</View>
</View>
^This is very close to what I want, but by default it looks like resizeMode:"Cover" just zooms in on the center of the image, cutting off my important content.
Is there any way to complete the image resizing based on something like x:0, y: screenHeight so that it keeps the top left of my image and resizes from the bottom right?
Import necessary packages
import { StyleSheet, Image, Dimensions } from 'react-native';
Your img element
<Image style={styles.images} resizeMode="stretch" source={{ uri: 'src here' }} />
Add this styles at the bottom
const styles = StyleSheet.create({
images: {
width: Dimensions.get('window').width,
height: Dimensions.get('window').width / 2
}
});
Try this the image width will be dynamically set even when you rotate your device.

how to create circle shape in react native with flex box

this is my component:
const styles = {
menuContainer: {
flex: 1,
flexDirection: 'column'
},
menuItem: {
flex: 1,
borderRadius: ??
}
}
<View style={styles.menuContainer}>
<TouchableOpacity {styles.menuItem}/>
<TouchableOpacity {styles.menuItem}/>
</View>
bordeRadius in react native doesn't work with percentage like 50% and in flex box i don't know the width of each flexItem. do you have any idea without calculate width of each flexItem?
Bad news, If you don't know the container's dimensions ahead of time, then I think you're only option is to use onLayout to calculate each flex container's dimensions.
{nativeEvent: { layout: {x, y, width, height}}}
If you can declare a fixed width & height, then it's easy, but sounds like this isn't going to be news to you.
circle: {
width: 100,
height: 100,
borderRadius: 100/2
}
There's a feature request submitted on this feature already. Show your support by up-voting it here...
https://react-native.canny.io/feature-requests/p/borderradius-percentages
Sorry!
I think that we cannot give border-radius to the flex so we can use width and height by getting device Dimensions and give the border-radius to the view.

React Native: print full image in a Scrollview

I have an image that is very tall, but not very large. I want to print it in a scrollview, so you can see it all on one screen, but nothing works.
after playing with widths and heights and flexs for my scrollview and my image, the best result I get is when I have on of them with style={{width='100%'}}, like that
<ScrollView style={{width: '100%'}}>
<Image
source={require('./assets/skeleton/fullSkeleton.png')}
resizeMode='cover'
/>
</ScrollView>
which prints the image at full width, but the scrollview's height is the original image's height, which doesn't let me see the whole resized image.
Here, a bad drawing to represent my image, and what I want to see on my phone screen
EDIT:
With this bit of code:
<ScrollView
contentContainerStyle={{alignItems: 'center'}}>
<Image
source={require('./fullSkeleton.png')}
resizeMode='cover'
/>
</ScrollView>
I end up with
Which can be scrolled down to see the rest of the Image. As you can see, it can be navigated vertically, but doesn't take the whole screen's width
This kind of thing in Reat Native is actually quite tricky. But you can do it easily; First get picture dimensions:
const FullWidthPicture = ({ uri }) => {
const [ratio, setRatio] = useState(1);
useEffect(() => {
if (uri) {
Image.getSize(uri, (width, height) => {
setRatio(width / height);
});
}
}, [uri]);
return (
<Image
style={{ width: '100%', height: undefined, aspectRatio: ratio }}
resizeMode="contain"
source={{ uri }}
/>
);
};
And use it like this:
<ScrollView style={{flex: 1}}>
<FulWidthImage uri={pictureUri} />
</ScrollView>
The following may help:
You can use contentContainerStyle to style the contents of the ScrollView. Like this (essentially what you have):
<ScrollView
contentContainerStyle={{alignItems: 'center'}}>
<Image
source={require('./fullSkeleton.png')}
resizeMode='cover'
/>
</ScrollView>
That works for me - I can scroll down the whole image and at the bottom it stays visible.
NB: To make the image cover the whole screen while maintaining the height required, you will need to set the width specifically. In my case on iPhone 7+ that meant adding style={{width: 414}} to the Image component AND changing resizeMode to 'stretch'.
Here is the official take on Image resizing...and getting device dimensions will be useful here too.