Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

View nested inside Camera component doesn't show up in view shot #492

Open
JordanHe opened this issue Aug 24, 2023 · 2 comments
Open

View nested inside Camera component doesn't show up in view shot #492

JordanHe opened this issue Aug 24, 2023 · 2 comments

Comments

@JordanHe
Copy link

JordanHe commented Aug 24, 2023

I want to put some overlays ontop of my camera view so that when the shot is taken by view shot it will be a picture with the overlays ontop.
My issue is that when I put my component nested inside the component it doesn't show up in the result of the view-shot.

If I just do the Overlay then it works but once I nest it inside the Camera component ( using expo-camera import { Camera, CameraType } from "expo-camera"; ) only the camera shows up in the view-shot when I take it.

I have tried adding collapsable={false} to all my views inside the component but that doesn't fix it.
Is there something I am doing wrong?

import { Camera, CameraType } from "expo-camera";
import { useEffect, useRef, useState } from "react";
import {
  Button,
  Dimensions,
  Platform,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
  Image,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { Stack, useRouter } from "expo-router";
import Overlay from "./components/overlay";

import ViewShot from "react-native-view-shot";
  const MyComponent: React.FC = () => {
  const viewShotRef = useRef<ViewShot | null>(null);
  const [screenshotUri, setScreenshotUri] = useState<string>("");

  const handleRetake = () => {
    setScreenshotUri("");
  };

  const handleCapture = async () => {
    console.log("viewShotRef.current=", viewShotRef.current);
    if (viewShotRef.current) {
      try {
        const uri = await viewShotRef.current.capture!();
        console.log("Captured and do something with ", uri);
        setScreenshotUri(uri);
      } catch (error) {
        console.error("Capture failed:", error);
      }
    }
  };

  const [type, setType] = useState(CameraType.front);
  const [permission, requestPermission] = Camera.useCameraPermissions();

  const [camera, setCamera] = useState<Camera | null>(null);

  const toggleCameraType = () => {
    setType((current) =>
      current === CameraType.back ? CameraType.front : CameraType.back,
    );
  };

  const [hasCameraPermission, setHasCameraPermission] = useState<boolean>();
  // Screen Ratio and image padding
  const [imagePadding, setImagePadding] = useState(0);
  const [ratio, setRatio] = useState("4:3"); // default is 4:3
  const { height, width } = Dimensions.get("window");
  const screenRatio = height / width;
  const [isRatioSet, setIsRatioSet] = useState(false);

  // on screen  load, ask for permission to use the camera
  useEffect(() => {
    const getCameraStatus = async () => {
      const request = await requestPermission();
      setHasCameraPermission(request.granted);
    };
    getCameraStatus();
  }, []);


  const prepareRatio = async () => {
    let desiredRatio = "4:3";
    if (Platform.OS === "android" && camera) {
      const ratios = await camera.getSupportedRatiosAsync();

      // .....  ratio calculation
      setImagePadding(remainder);
      setRatio(desiredRatio);
      setIsRatioSet(true);
    }
  };


  const setCameraReady = async () => {
    if (!isRatioSet) {
      await prepareRatio();
    }
  };

  if (hasCameraPermission === null) {
    return (
      <View className="flex-1 items-center justify-center self-center">
        <Text>Waiting for camera permissions</Text>
      </View>
    );
  } else if (hasCameraPermission === false) {
    return (
      <View className="flex-1 items-center justify-center self-center">
        <Text>No access to camera</Text>
      </View>
    );
  } else {
    return (
      <SafeAreaView className="flex-1">
        <Stack.Screen options={{ title: "Live" }} />
        <View className="flex-1 justify-center bg-neutral-800">
          {/* 
        We created a Camera height by adding margins to the top and bottom, 
        but we could set the width/height instead 
        since we know the screen dimensions
        */}
          {screenshotUri == "" ? (
            <ViewShot ref={viewShotRef} style={{ flex: 1 }}>
              <Camera
                style={{
                  flex: 1,
                  //   marginTop: imagePadding,
                  marginBottom: imagePadding,
                }}
                onCameraReady={setCameraReady}
                ratio={ratio}
                type={type}
                ref={(ref) => {
                  setCamera(ref);
                }}
              >
              <Overlay
                toggleCameraType={toggleCameraType}
                handleCapture={handleCapture}
                distance={1.32}
                duration={4.55}
              />
              </Camera>
            </ViewShot>
          ) : (
            <View>
              <TouchableOpacity
                onPress={handleRetake}
                className="absolute left-2 top-2 z-10"
              >
                <Text>Retake</Text>
              </TouchableOpacity>
              <Image
                source={{ uri: screenshotUri }}
                style={{
                  height: undefined,
                  width: "100%",
                  aspectRatio: 9 / 16,
                  alignSelf: "center",
                }}
              />
            </View>
          )}
        </View>
      </SafeAreaView>
    );
  }

Version & Platform

using react native expo (managed workflow, not expo go) version number of react-native-view-shot is "react-native-view-shot": "3.5.0",

**Platform: Android

component below

import { TouchableOpacity, View, Text, Image } from "react-native";
import ff from "../../utils/globalStyles";
import run from "../../workout/run";
import { Ionicons } from "@expo/vector-icons";
import { Entypo } from "@expo/vector-icons";
import { useRouter } from "expo-router";

type OverlayProps = {
  toggleCameraType: () => void;
  handleCapture: () => Promise<void>;
  distance: number;
  duration: number;
};

const Overlay: React.FC<OverlayProps> = ({
  toggleCameraType,
  handleCapture,
  distance,
  duration,
}) => {
  const router = useRouter();

  return (
    <View className="z-10 h-full justify-between" collapsable={false}>
      <View className="flex-row justify-between px-2 pt-4" collapsable={false}>
        <TouchableOpacity onPress={() => router.back()}>
          <Entypo name="cross" size={36} color="white" />
        </TouchableOpacity>
        <Image
          source={require("../../workout/img/myImage.png")}
          style={{
            height: undefined,
            width: 140,
            aspectRatio: 2.7,
            alignSelf: "center",
          }}
        />
        <View className="w-9" />
      </View>

   


      <View className="flex-row justify-between px-10 pb-4" collapsable={false}>
        <View className="w-12" />
        <TouchableOpacity onPress={handleCapture}>
          <View
            className="h-20 w-20 justify-center rounded-full bg-white"
            style={{ opacity: 0.5 }}
          >
            <View className="h-16 w-16 self-center rounded-full bg-white"></View>
          </View>
        </TouchableOpacity>
        <TouchableOpacity onPress={toggleCameraType} className="justify-center">
          <Ionicons name="ios-camera-reverse-outline" size={48} color="white" />
        </TouchableOpacity>
      </View>
    </View>
  );
};

export default Overlay;
@aindong
Copy link

aindong commented Dec 20, 2023

Hi @JordanHe were you able to solve this?

@tructtyoong
Copy link

same issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants