Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overlay button on top of Image in React Native

I'm trying to achieve the following effect in React Native:

image with an icon in the corner

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:

portrait image with button overlay 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>
like image 567
Keith Kurak Avatar asked Oct 05 '17 01:10

Keith Kurak


People also ask

How do I add an overlay to an image in React Native?

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.

How do you put one element on top of another React Native?

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.

How do I add text on top of an image in React Native?

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', }, });


3 Answers

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 :

enter image description here

like image 95
Ozesh Avatar answered Oct 05 '22 08:10

Ozesh


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>
like image 31
Stanislau Buzunko Avatar answered Oct 05 '22 06:10

Stanislau Buzunko


Updated 29 Jun 2019

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.


Original Answer

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>
like image 35
Oboo Cheng Avatar answered Oct 05 '22 06:10

Oboo Cheng