javascript - I can't seem to find out why my code is failing to get a snapshot in my react expo project - Stack Overflow

import { View, StyleSheet, Platform } from 'react-native';import * as ImagePicker from '

import { View, StyleSheet, Platform } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import { useState, useRef } from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import * as MediaLibrary from 'expo-media-library';
import { captureRef } from 'react-native-view-shot';
import { type ImageSource } from "expo-image";

import Button from '@/components/Button';
import ImageViewer from '@/components/ImageViewer';
import IconButton from '@/components/IconButton';
import CircleButton from '@/components/CircleButton';
import EmojiPicker from '@/components/EmojiPicker';
import EmojiList from '@/components/EmojiList';
import EmojiSticker from '@/components/EmojiSticker';

const PlaceholderImage = require('@/assets/images/background-image.png');

export default function Index() {
  const [selectedImage, setSelectedImage] = useState<string | undefined>(undefined);
  const [showAppOptions, setShowAppOptions] = useState<boolean>(false);
  const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
  const [pickedEmoji, setPickedEmoji] = useState<ImageSource | undefined>(undefined);
  const [status, requestPermission] = MediaLibrary.usePermissions();
  const imageRef = useRef<View>(null);

  if (status === null) {
    requestPermission();
  }

  const pickImageAsync = async () => {
    let result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ['images'],
      allowsEditing: true,
      quality: 1,
    });

    if (!result.canceled) {
      setSelectedImage(result.assets[0].uri);
      setShowAppOptions(true);
    } else {
      alert('You did not select any image.');
    }
  };

  const onReset = () => {
    setShowAppOptions(false);
  };

  const onAddSticker = () => {
    setIsModalVisible(true);
  };

  const onModalClose = () => {
    setIsModalVisible(false);
  };
`problematic function`
  const onSaveImageAsync = async () => {
    try {
      if (!imageRef.current) {
        throw new Error('View reference is not available');
      }

      const localUri = await captureRef(imageRef.current, {
        height: 440,
        quality: 1,
        format: 'png', // Explicitly set format
        result: Platform.OS === 'ios' ? 'tmpfile' : 'data-uri', // Different result types for iOS/Android
      });

      if (!localUri) {
        throw new Error('Failed to capture view');
      }

      await MediaLibrary.saveToLibraryAsync(localUri);
      alert('Saved!');
    } catch (e) {
      console.log(e);
    }
  };

  return (
    <GestureHandlerRootView style={styles.container}>
      <View style={styles.imageContainer}>
        <View ref={imageRef} collapsable={false}>
          <ImageViewer imgSource={PlaceholderImage} selectedImage={selectedImage} />
          {pickedEmoji && <EmojiSticker imageSize={40} stickerSource={pickedEmoji} />}
        </View>
      </View>
      {showAppOptions ? (
        <View style={styles.optionsContainer}>
          <View style={styles.optionsRow}>
            <IconButton icon="refresh" label="Reset" onPress={onReset} />
            <CircleButton onPress={onAddSticker} />
            <IconButton icon="save-alt" label="Save" onPress={onSaveImageAsync} />
          </View>
        </View>
      ) : (
        <View style={styles.footerContainer}>
          <Button theme="primary" label="Choose a photo" onPress={pickImageAsync} />
          <Button label="Use this photo" onPress={() => setShowAppOptions(true)} />
        </View>
      )}
      <EmojiPicker isVisible={isModalVisible} onClose={onModalClose}>
        <EmojiList onSelect={setPickedEmoji} onCloseModal={onModalClose} />
      </EmojiPicker>
    </GestureHandlerRootView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#25292e',
    alignItems: 'center',
  },
  imageContainer: {
    flex: 1,
  },
  footerContainer: {
    flex: 1 / 3,
    alignItems: 'center',
  },
  optionsContainer: {
    position: 'absolute',
    bottom: 80,
  },
  optionsRow: {
    alignItems: 'center',
    flexDirection: 'row',
  },
});

this is the page im getting the problem, the error is probably something with the onSaveImageAsync function. I could not get ChatGPT to find the problem

the message I get when I try to save is

[Error: Failed to snapshot view tag 14]

I tried asking ChatGPT and Claudia but they could not help,

this code is also the original tutorial code from /tutorial/screenshot/

import { View, StyleSheet, Platform } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import { useState, useRef } from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import * as MediaLibrary from 'expo-media-library';
import { captureRef } from 'react-native-view-shot';
import { type ImageSource } from "expo-image";

import Button from '@/components/Button';
import ImageViewer from '@/components/ImageViewer';
import IconButton from '@/components/IconButton';
import CircleButton from '@/components/CircleButton';
import EmojiPicker from '@/components/EmojiPicker';
import EmojiList from '@/components/EmojiList';
import EmojiSticker from '@/components/EmojiSticker';

const PlaceholderImage = require('@/assets/images/background-image.png');

export default function Index() {
  const [selectedImage, setSelectedImage] = useState<string | undefined>(undefined);
  const [showAppOptions, setShowAppOptions] = useState<boolean>(false);
  const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
  const [pickedEmoji, setPickedEmoji] = useState<ImageSource | undefined>(undefined);
  const [status, requestPermission] = MediaLibrary.usePermissions();
  const imageRef = useRef<View>(null);

  if (status === null) {
    requestPermission();
  }

  const pickImageAsync = async () => {
    let result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ['images'],
      allowsEditing: true,
      quality: 1,
    });

    if (!result.canceled) {
      setSelectedImage(result.assets[0].uri);
      setShowAppOptions(true);
    } else {
      alert('You did not select any image.');
    }
  };

  const onReset = () => {
    setShowAppOptions(false);
  };

  const onAddSticker = () => {
    setIsModalVisible(true);
  };

  const onModalClose = () => {
    setIsModalVisible(false);
  };
`problematic function`
  const onSaveImageAsync = async () => {
    try {
      if (!imageRef.current) {
        throw new Error('View reference is not available');
      }

      const localUri = await captureRef(imageRef.current, {
        height: 440,
        quality: 1,
        format: 'png', // Explicitly set format
        result: Platform.OS === 'ios' ? 'tmpfile' : 'data-uri', // Different result types for iOS/Android
      });

      if (!localUri) {
        throw new Error('Failed to capture view');
      }

      await MediaLibrary.saveToLibraryAsync(localUri);
      alert('Saved!');
    } catch (e) {
      console.log(e);
    }
  };

  return (
    <GestureHandlerRootView style={styles.container}>
      <View style={styles.imageContainer}>
        <View ref={imageRef} collapsable={false}>
          <ImageViewer imgSource={PlaceholderImage} selectedImage={selectedImage} />
          {pickedEmoji && <EmojiSticker imageSize={40} stickerSource={pickedEmoji} />}
        </View>
      </View>
      {showAppOptions ? (
        <View style={styles.optionsContainer}>
          <View style={styles.optionsRow}>
            <IconButton icon="refresh" label="Reset" onPress={onReset} />
            <CircleButton onPress={onAddSticker} />
            <IconButton icon="save-alt" label="Save" onPress={onSaveImageAsync} />
          </View>
        </View>
      ) : (
        <View style={styles.footerContainer}>
          <Button theme="primary" label="Choose a photo" onPress={pickImageAsync} />
          <Button label="Use this photo" onPress={() => setShowAppOptions(true)} />
        </View>
      )}
      <EmojiPicker isVisible={isModalVisible} onClose={onModalClose}>
        <EmojiList onSelect={setPickedEmoji} onCloseModal={onModalClose} />
      </EmojiPicker>
    </GestureHandlerRootView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#25292e',
    alignItems: 'center',
  },
  imageContainer: {
    flex: 1,
  },
  footerContainer: {
    flex: 1 / 3,
    alignItems: 'center',
  },
  optionsContainer: {
    position: 'absolute',
    bottom: 80,
  },
  optionsRow: {
    alignItems: 'center',
    flexDirection: 'row',
  },
});

this is the page im getting the problem, the error is probably something with the onSaveImageAsync function. I could not get ChatGPT to find the problem

the message I get when I try to save is

[Error: Failed to snapshot view tag 14]

I tried asking ChatGPT and Claudia but they could not help,

this code is also the original tutorial code from https://docs.expo.dev/tutorial/screenshot/

Share Improve this question edited Nov 19, 2024 at 17:08 Barmar 784k57 gold badges548 silver badges659 bronze badges asked Nov 19, 2024 at 5:05 Eyuphan TilkiEyuphan Tilki 11 bronze badge 2
  • There are several alternative solutions which you can try. They might or might not work. - Adding collapsable={false} to the View component which you want to capture. This might temporarily fix this issue. - Test with Android and iOS. This issue might happen in Android but not in iOS. - Change from View to ViewShot tag. – Alex Commented Nov 19, 2024 at 13:50
  • "I tried asking ChatGPT and Claudia but they could not help," does not feel like it adds any useful information to your question. In fact, I'm hoping it's true of every question asked on Stack Overflow that the asker has spent a reasonable amount of effort on answering their own question using the various of resources available to us the internet. If it had helped, you wouldn't be asking. – Wyck Commented Nov 19, 2024 at 14:11
Add a comment  | 

2 Answers 2

Reset to default 0

If you're using Expo SDK 52, the issue is likely related to that. I recently updated from SDK 51 to 52 and experienced the same error. This update also involved upgrading the react-native-view-shot library from version 3.8.0 to 4.0.0.

it works changing snapshotContentContainer: true to snapshotContentContainer: false

with expo 52

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745581045a4634258.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信