I'm trying to achieve the following effect in React Native:
The image has a button in the corner. The button is always within the corner of the image regardless of the image's size or aspect ratio, and no part of the image is clipped (it is always scaled down to fit fully within a box).
The trouble I'm having in React Native is that the Image component's size doesn't always match the scaled-down size of the image. If I fix the image's height to 300, set flex 1 to make the image's width expand to fill its contents, and the image is a portrait, the Image component with being the full width of the container, but the image within the component will have a width of much less. Therefore, the typical approach for having a view overlay another view doesn't work as I would like it to- my overlay also covers the padding around the image, and the button (anchored to the corner) appears outside of the image.
Here's what it looks like in React Native:
The X is a placeholder for the button. It is set to anchor to the top-left of a View that's a child of the same View that the Image is a child of. The backgroundColor of the image is set to green to demonstrate how the width of the Image component is different from the width of the picture that's inside the component.
The goal is that the X would be inside of the image regardless of its aspect ratio. I think I could do something based on grabbing the image's dimension and scaling the height and width of the Image component, but that sounds complicated and fragile. Is this possible in a responsive way with styling?
Demonstration code:
<View
style={{
marginLeft: 7,
marginRight: 7,
backgroundColor: 'blue',
}}
>
<View
style={{
height: 300,
flex: 1,
}}
>
<Image
source={imageSource}
style={{
flex: 1,
height: undefined,
width: undefined,
backgroundColor: 'green',
}}
resizeMode="contain"
/>
</View>
<View
style={{
position: 'absolute',
right: 5,
top: 5,
backgroundColor: 'transparent',
}}
>
<Text style={{ color: 'white' }}>X</Text>
</View>
</View>
To add a transparent overlay in React Native, we can use the ImageBackground component. to add an ImageBackground with the source set to an object with the uri of the background image. And we add the backgroundImage style that sets opacity to 0.3 to add a transparent overlay over the image.
We use the style property position to align one view over another. The position of the view which is beneath the surface should be made relative whereas the position of views above it should be absolute. Make use of properties such as top, left, right and bottom to align the views.
create({ container: { flex: 1, }, coverImage: { width: '100%', height: 200, }, textView: { position: 'absolute', justifyContent: 'center', alignItems: 'center', top: 0, left: 0, right: 0, bottom: 0, }, imageText: { fontSize: 20, color: 'white', fontWeight: 'bold', }, });
Here is how I accomplished that:
import React, { Component } from "react";
import { View, Image, StyleSheet } from "react-native";
import { Ionicons } from "@expo/vector-icons";
class MyCard extends Component {
render() {
return (
<View style={styles.container}>
<Image
resizeMode="cover"
style={styles.cover}
source={{ uri: "https://picsum.photos/700" }}
/>
<Ionicons style={styles.close} name="ios-close-circle" size={25} />
</View>
);
}
}
export default MyCard;
const styles = StyleSheet.create({
container: {
margin: 5,
width: 160,
height: 200
},
cover: {
flex: 1,
borderRadius: 5
},
close: {
margin: 5,
position: "absolute",
top: 0,
left: 0,
width: 25,
height: 25,
color: "tomato"
}
});
Here is how it looks like :
From React-native v0.50.0 <Image>
with nested content is no longer supported. Use <ImageBackground>
instead.
<ImageBackground
source={imageSource}
>
<View>
<Text>×</Text>
</View>
</ImageBackground>
Now([email protected]
) there's a specific component to wrap elements as image background, ImageBackground. Go for the official documentation.
Following Gist has been changed.
We can use <Image/>
display images, and we can use it as a background-image
hack.
try this
<Image
source={imageSource}
>
<View>
<Text>×</Text>
</View>
</Image>
this gist is a full demo for your need.
or you can see it live at expo:
<div data-snack-id="B1SsJ7m2b" data-snack-platform="ios" data-snack-preview="true" data-snack-theme="light" style="overflow:hidden;background:#fafafa;border:1px solid rgba(0,0,0,.16);border-radius:4px;height:505px;width:100%"></div>
<script async src="https://snack.expo.io/embed.js"></script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With