React Native Animated - запуск анимации при касании

Играю с анимацией в React Native. Хотите создать экран, позволяющий пользователю касаться экрана в любой момент. Когда они это сделают, на месте их пальца должен появиться круг и следовать за ним. Когда они отпускаются, круг должен уменьшиться до нуля.

Я начал следовать этот учебник, который предназначен для анимации, похожей на пружину, в которой вы перетаскиваете уже существующий квадрат (который начинается в центре экрана), и он возвращается в исходное состояние при отпускании.

В моем случае у круга должно быть уже существующее местоположение нет, и это вызывает проблему. Если я инициализирую состояние своего компонента, скажем, с помощью pan: new Animated.ValueXY(), а затем касаюсь экрана, кружок начинается в верхнем левом углу, нет, где находится мой палец. Я пробовал множество других решений, все заменяя закомментированную строку в методе onPanResponderGrant ниже, но, похоже, не могу понять это.

Как сделать анимацию, в которой компонент просто отслеживает мой палец, никуда не запускаясь и не возвращаясь?

Вот код компонента:

class FollowCircle extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      pan: new Animated.ValueXY(),
      scale: new Animated.Value(0)
    };
  }

  componentWillMount() {
    this._panResponder = PanResponder.create({
      onStartShouldSetPanResponderCapture: () => true,
      onMoveShouldSetPanResponderCapture: () => true,

      onPanResponderGrant: (e, gestureState) => {
        // This is the line I'm playing with
        this.state.pan.setValue({ x: this.state.pan.x._value, y: this.state.pan.y._value });

        Animated.spring(
          this.state.scale,
          { toValue: 1, friction: 3 },
        ).start();
      },

      onPanResponderMove: Animated.event([
        null, { dx: this.state.pan.x, dy: this.state.pan.y }
      ]),

      onPanResponderRelease: (/* e, gestureState */) => {
        this.state.pan.flattenOffset();
        Animated.spring(
          this.state.scale,
          {
            toValue: 0,
            friction: 10,
            restDisplacementThreshold: 1
          },
        ).start();
      }
    });
  }

  render() {
    const { pan, scale } = this.state;
    const circleStyles = {
      backgroundColor: 'black',
      width: 50,
      height: 50,
      borderRadius: 25,
      transform: [
        { translateX: pan.x },
        { translateY: pan.y },
        { scale }
      ]
    };

    return (
      <AppWrapper navigation = { this.props.navigation }>
        <Animated.View
          style = { {
            flex: 1,
            width: Dimensions.get('window').width,
            height: Dimensions.get('window').height,
            backgroundColor: 'white'
          } }
          { ...this._panResponder.panHandlers }
        >
          <Animated.View
            style = { circleStyles }
          />
        </Animated.View>
      </AppWrapper>
    );
  }
};

И вот мои альтернативные попытки (замены закомментированной строки):

this.state.pan.setValue({ x: gestureState.x0, y: gestureState.y0 });

И этот:

  if (this.state.pan) {
    this.state.pan.setValue({ x: this.state.pan.x._value, y: this.state.pan.y._value });
  } else {
    this.setState({ pan: new Animated.ValueXY(gestureState.x0, gestureState.y0) });
  }

Оба, кажется, ведут себя одинаково, сбрасывая положение круга в верхнем левом углу после каждого движения и не совсем отслеживая местоположение моего пальца, если я не начинаю касание в этом источнике.

Есть идеи, как это сделать правильно?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
1 744
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В итоге я понял это, заменив материал panResponder на TouchableHighlight размером со страницу с событием onTouch.

Это событие запустило следующую функцию, которая получает местоположение nativeEvent.pageX и pageY и использует его. Мне пришлось внести небольшие изменения в расположение y, чтобы оно работало на всех телефонах:

  triggerSwipe({ nativeEvent }) {
    const coordinates = { x: nativeEvent.pageX, y: nativeEvent.pageY };
    const self = this;
    if (!this.state.animating) {
      this.setState({
        x: coordinates.x,
        y: coordinates.y + (this.windowHeight / 2.5),
        animating: true
      }, () => {
        Animated.timing(
          self.state.scale,
          { toValue: 20, duration: 600 },
        ).start(() => {
          this.setState({
            scale: new Animated.Value(0.01), // See Notes.md for reasoning
            colorIndex: this.state.colorIndex + 1,
            animating: false
          });
        });
      });
    }

Анимирующий круг представляет собой Animated.View внутри TouchableHighlight, которому передаются координаты касания.

Другие вопросы по теме