如何解决 Reanimated 中的“只能在 UI 运行时直接从 _value 读取”?

问题描述 投票:0回答:1

我正在 React Native 中开发一个应用程序,该应用程序使用 Google ML Kit 的 PoseDetection API。 这是我大学的一个项目。 这是我的 package.json:

"dependencies": {
    "metro-react-native-babel-preset": "^0.77.0",
    "react": "18.2.0",
    "react-native": "0.73.6",
    "react-native-gesture-handler": "^2.14.0",
    "react-native-reanimated": "^3.6.2",
    "react-native-svg": "^15.3.0",
    "react-native-vision-camera": "^4.0.5",
    "react-native-worklets-core": "^1.3.3"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@babel/plugin-proposal-class-properties": "^7.18.6",
    "@babel/plugin-transform-private-methods": "^7.24.7",
    "@babel/preset-env": "^7.20.0",
    "@babel/runtime": "^7.20.0",
    "@react-native/babel-preset": "0.74.84",
    "@react-native/eslint-config": "0.74.84",
    "@react-native/metro-config": "0.74.84",
    "@react-native/typescript-config": "0.74.84",
    "@types/react": "^18.2.6",
    "@types/react-test-renderer": "^18.0.0",
    "babel-jest": "^29.6.3",
    "eslint": "^8.19.0",
    "jest": "^29.6.3",
    "prettier": "2.8.8",
    "react-test-renderer": "18.2.0",
    "typescript": "5.0.4"
  },

还有我的 App.tsx:

import React, { useEffect } from 'react';
import { Dimensions, Platform, StyleSheet, Text, useWindowDimensions, View } from 'react-native';
import { Camera, useFrameProcessor, useCameraDevice } from 'react-native-vision-camera';
import Animated, { useSharedValue, useAnimatedProps, useAnimatedStyle } from 'react-native-reanimated';
import Svg, { Line } from 'react-native-svg';
import { __poseDetection } from './FrameProcessorPlugin';
import 'react-native-worklets-core';

const AnimatedLine = Animated.createAnimatedComponent(Line);

const usePosition = (pose, valueName1, valueName2) => {
  return useAnimatedProps(
    () => ({
      x1: pose.value[valueName1].x,
      y1: pose.value[valueName1].y,
      x2: pose.value[valueName2].x,
      y2: pose.value[valueName2].y,
    }),
    [pose],
  );
};

export function objectDetect(frame) {
  'worklet';
  return __poseDetection(frame);
}

const defaultPose = {
  leftShoulder: { x: 0, y: 0 },
  rightShoulder: { x: 0, y: 0 },
  leftElbow: { x: 0, y: 0 },
  rightElbow: { x: 0, y: 0 },
  leftWrist: { x: 0, y: 0 },
  rightWrist: { x: 0, y: 0 },
  leftHip: { x: 0, y: 0 },
  rightHip: { x: 0, y: 0 },
  leftKnee: { x: 0, y: 0 },
  rightKnee: { x: 0, y: 0 },
  leftAnkle: { x: 0, y: 0 },
  rightAnkle: { x: 0, y: 0 },
};

const App = () => {
  const pose = useSharedValue(defaultPose);

  const leftWristToElbowPosition = usePosition(pose, 'leftWrist', 'leftElbow');
  const leftElbowToShoulderPosition = usePosition(pose, 'leftElbow', 'leftShoulder');
  const leftShoulderToHipPosition = usePosition(pose, 'leftShoulder', 'leftHip');
  const leftHipToKneePosition = usePosition(pose, 'leftHip', 'leftKnee');
  const leftKneeToAnklePosition = usePosition(pose, 'leftKnee', 'leftAnkle');

  const rightWristToElbowPosition = usePosition(pose, 'rightWrist', 'rightElbow');
  const rightElbowToShoulderPosition = usePosition(pose, 'rightElbow', 'rightShoulder');
  const rightShoulderToHipPosition = usePosition(pose, 'rightShoulder', 'rightHip');
  const rightHipToKneePosition = usePosition(pose, 'rightHip', 'rightKnee');
  const rightKneeToAnklePosition = usePosition(pose, 'rightKnee', 'rightAnkle');

  const shoulderToShoulderPosition = usePosition(pose, 'leftShoulder', 'rightShoulder');
  const hipToHipPosition = usePosition(pose, 'leftHip', 'rightHip');

  const dimensions = useWindowDimensions();

  const frameProcessor = useFrameProcessor((frame) => {
    'worklet';
    const poseObject = objectDetect(frame);

    const xFactor = dimensions.width / frame.width;
    const yFactor = dimensions.height / frame.height;

    const poseCopy = {
      leftShoulder: { x: 0, y: 0 },
      rightShoulder: { x: 0, y: 0 },
      leftElbow: { x: 0, y: 0 },
      rightElbow: { x: 0, y: 0 },
      leftWrist: { x: 0, y: 0 },
      rightWrist: { x: 0, y: 0 },
      leftHip: { x: 0, y: 0 },
      rightHip: { x: 0, y: 0 },
      leftKnee: { x: 0, y: 0 },
      rightKnee: { x: 0, y: 0 },
      leftAnkle: { x: 0, y: 0 },
      rightAnkle: { x: 0, y: 0 },
    };

    Object.keys(poseObject).forEach((v) => {
      poseCopy[v] = {
        x: poseObject[v].x * xFactor,
        y: poseObject[v].y * yFactor,
      };
    });

    pose.value = poseCopy;
  }, []);

  const device = useCameraDevice('back');

  useEffect(() => {
    const checkPermissions = async () => {
      await Camera.requestCameraPermission();
    };
    checkPermissions();
  }, []);

  if (device == null) {
    return <Text>Loading...</Text>;
  }

  return (
    <>
      <Camera
        frameProcessor={frameProcessor}
        style={StyleSheet.absoluteFill}
        device={device}
        isActive={true}
      />
      <Svg
        height={Dimensions.get('window').height}
        width={Dimensions.get('window').width}
        style={styles.linesContainer}>
        <AnimatedLine animatedProps={leftWristToElbowPosition} stroke="red" strokeWidth="2" />
        <AnimatedLine animatedProps={leftElbowToShoulderPosition} stroke="red" strokeWidth="2" />
        <AnimatedLine animatedProps={leftShoulderToHipPosition} stroke="red" strokeWidth="2" />
        <AnimatedLine animatedProps={leftHipToKneePosition} stroke="red" strokeWidth="2" />
        <AnimatedLine animatedProps={leftKneeToAnklePosition} stroke="red" strokeWidth="2" />
        <AnimatedLine animatedProps={rightWristToElbowPosition} stroke="red" strokeWidth="2" />
        <AnimatedLine animatedProps={rightElbowToShoulderPosition} stroke="red" strokeWidth="2" />
        <AnimatedLine animatedProps={rightShoulderToHipPosition} stroke="red" strokeWidth="2" />
        <AnimatedLine animatedProps={rightHipToKneePosition} stroke="red" strokeWidth="2" />
        <AnimatedLine animatedProps={rightKneeToAnklePosition} stroke="red" strokeWidth="2" />
        <AnimatedLine animatedProps={shoulderToShoulderPosition} stroke="red" strokeWidth="2" />
        <AnimatedLine animatedProps={hipToHipPosition} stroke="red" strokeWidth="2" />
      </Svg>
    </>
  );
};

const styles = StyleSheet.create({
  linesContainer: {
    position: 'absolute',
    top: 0,
    left: 0,
    height: Dimensions.get('window').height,
    width: Dimensions.get('window').width,
  },
});

export default App;

现在我希望应用程序能够启动相机并向我显示动画线条,这样我就知道姿势检测是有效的。但我收到以下错误: Error message of Android Emulator

我不太了解 React 和 Reanimated 中的很多语法。我该如何解决这个问题?

如果您需要更多信息,请告诉我。

我检查了类似的 GitHub 和 StackOF 问题,但都是由于错误导入引起的。根据解决方案,我的似乎没问题

就像我说的,我不太了解语法,所以我让 ChatGPT 更改了几次代码。但每个版本都会导致相同的错误。

我检查了 Reanimated 网站的故障排除部分。我的错误没有列在其中。

android react-native user-interface react-native-reanimated pose-detection
1个回答
0
投票

我在 GitHub 上发现了另一个问题,其中有人提到了他的错误,这与我的有点相似。 显然,在 Reanimated V3 上,当您使用“react-native-worklets-core”时,“useSharedValue”的导入必须是“react-native-worklets-core”。 所以解决办法是:

import React, { useEffect } from 'react';
import { Dimensions, Platform, StyleSheet, Text, useWindowDimensions, View } from 'react-native';
import { Camera, useFrameProcessor, useCameraDevice } from 'react-native-vision-camera';
import Animated, { useAnimatedProps, useAnimatedStyle } from 'react-native-reanimated'; //delete useSharedValue
import Svg, { Line } from 'react-native-svg';
import { poseDetect } from './objectDetect';
import { useSharedValue } from 'react-native-worklets-core'; //add it here
© www.soinside.com 2019 - 2024. All rights reserved.