White background in react-native-view-shot

983 Views Asked by At

I am using react-native-view-shot to save a screenshot of a view, whose height is not initially defined, as I am using padding and setting the height of the view using the onLayout method.

The problem is that, when the view has an initial fixed height, the screenshot taken does not have a white background, which is what I want. However, when I set the height when the onLayout is invoked, the screenshot has a white background.

Here's my code:

const [height, setHeight] = useState();

  <View
    onLayout={(e) => {
      setHeight(e.nativeEvent.layout.height);
    }}
    ref={contentRef}
    style={{
      height,
      width: width - 12,
      backgroundColor: "darkblue",
      borderRadius: 32,
    }}
  >
    <Text style={styles.text}>This is a test using padding</Text>
  </View>

https://snack.expo.dev/@pietroputelli/react-native-view-shot

=========== EDIT ===========

 <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
      <View ref={shotRef} style={{ backgroundColor: "transparent" }}>
        <View
          onLayout={(e) => {
            setHeight(e.nativeEvent.layout.height);
          }}
          style={{
            height,
            width: width / 2 - 12,
            backgroundColor: "darkblue",
            borderRadius: 32,
          }}
        >
          <Text style={{ color: "white" }}>This is a test using padding</Text>
        </View>
      </View>
      <Button
        onPress={() => {
          captureRef(shotRef, {
            format: "png",
            quality: 0.8,
          }).then(
            async (uri) => {
              await MediaLibrary.saveToLibraryAsync(uri);
            },
            (error) => console.error("Oops, snapshot failed", error)
          );
        }}
        title="Take screenshot"
      />
    </View>
2

There are 2 best solutions below

14
On

I can able to generate the same from viewshot: take another view and give a reference to that view and generate a screenshot from that. might be its issue of reference. Please check the below screenshot.

enter image description here

            <View ref={viewshotRef}
                style={{
                    // whatever you want to add as per your requirement 
                }} >
                <View
                    onLayout={(e) => {
                        setHeight(e.nativeEvent.layout.height);
                    }}
                    style={{
                        height,
                        width: DEVICE_WIDTH / 2 - 12,
                        backgroundColor: "darkblue",
                        borderRadius: 32,
                    }}
                >
                    <Text style={{ color: 'white' }}>This is a test using padding</Text>
                </View>
            </View>

For base64:

import * as MediaLibrary from "expo-media-library";
import React, { useRef, useState } from "react";
import {
    Button,
    Dimensions,
    StyleSheet,
    Text,
    View,
} from "react-native";
import ViewShot, { captureRef } from "react-native-view-shot";

const { width } = Dimensions.get("window");

export default function ViewCapture() {
    const contentRef = useRef();

    const [height, setHeight] = useState(undefined);

    return (
        <View style={{ flex: 1, justifyContent: "center", alignItems: "center", backgroundColor: "transparent" }}>
            <ViewShot ref={contentRef} options={{ result: 'base64' }}>
                <View
                    onLayout={(e) => {
                        setHeight(e.nativeEvent.layout.height);
                    }}
                    style={{
                        height,
                        width: width - 12,
                        backgroundColor: "darkblue",
                        borderRadius: 32,
                    }}
                >
                    <Text style={{ color: "white" }}>This is a test using padding</Text>
                </View>
            </ViewShot>
            {/* </View> */}

            <Button
                onPress={() => {
                    contentRef.current.capture().then((url) => {
                        console.log("on success", "data:image/jpeg;base64,", url)
                        //   await MediaLibrary.saveToLibraryAsync(uri);
                    },
                        (error) => console.error("Oops, snapshot failed", error)
                    );
                }}
                title="Take screenshot"
            />
        </View>

    );
}

For File:

You need to set the result as tmpfile so you will get file uri in the callback

   <ViewShot ref={contentRef} options={{ result: 'tmpfile' }}>

I hope it will work!

0
On

I was able to get transparency when I set the format to "png" in the options parameter for captureRef. PNGs can show a transparency, "jpgs" cannot: https://stackoverflow.com/questions/16906144/transparent-background-in-jpeg-image#:~:text=JPEG%20can't%20support%20transparency,%2C%20a%20%3D%20alpha%20value).

(And for me, I was trying to show rounded corners. I just had to set the outer component style to have borderRadius with no background colour, but the child had a backgroundColor)

const viewRef = useRef() as React.MutableRefObject<ViewShot>;

// ... 

const onClickDownload = async () => {
  try {
     const uri = await captureRef(viewRef, {
       fileName: entryFilename,
       format: "png", 
       quality: 0.9,
     });

     // ... 
  } 
}

Using: https://github.com/gre/react-native-view-shot