React Native Animated - Расширить круг по центру прессы - PullRequest
0 голосов
/ 12 сентября 2018

Я пытаюсь создать компонент, используя Animated на React Native, где круг расширяется от точки печати, чтобы охватить весь экран.

Идея состоит в том, что, по сути, существует карусель цветов, скажем:

const colors = ['white', 'black', 'green', 'blue', 'red', 'pink'];

Вы начинаете с цвета 0 в качестве фона, а затем, когда вы нажимаете на экран, круг цвета 1 расширяется (из ничего) от точки нажатия и занимает весь экран,В этот момент, когда анимация завершена, colorIndex увеличивается, и анимированный круг одновременно стирается, так что мы плавно перешли к следующему цвету, который теперь является фоном.(Например, теперь цвет фона «черный»).

Затем, когда вы нажимаете снова, процесс повторяется, расширяя круг «зеленого», чтобы заполнить экран, затем обновляя зеленый, чтобы быть цветом BG, и т. Д.

(Чтобы уточнить, чтоЯ ищу в анимации, отметьте этот GIF (без значков и т. Д.)).

Я пытаюсь сделать это с помощью Animated, и код, подобный следующему, вызываетсянажатие основного фонового компонента (TouchableHighlight):

triggerSwipe(event) {
  this.setState({ location: { x: event.nativeEvent.locationX, y: event.nativeEvent.locationY } });

  Animated.timing(
    this.state.diameter,
    { toValue: Dimensions.get('window').height * 2, duration: 500 },
  ).start(() => {
    this.state.diameter.setValue(0);
    this.setState({ colorIndex: this.state.colorIndex + 1 });
  });
}

Тогда идея состоит в том, чтобы в функции render я установил left и top моего absolute только расположенного компонента кругаравное местоположение, и я устанавливаю width и height равными diameter, а также borderRadius (diameter / 2.0 не будет работать, потому что diameter является Анимированным объектом, а не числом).

Здесь происходит две проблемы, которые я не могу понять (обе они видны в GIF, включенном в нижней части этого вопроса):

  1. Есть черныймигать перед каждой анимацией.Он охватывает весь компонент TouchableHighlight.И всегда черный.Какого бы цвета я ни был.В компоненте отсутствует черный код (!).
  2. Местоположение определяет край круга (или, точнее, квадрат, внутри которого он транскрибируется), а не центр.Я хочу, чтобы он определил центр круга, чтобы круг расширялся наружу от моего пресса.

Я предполагаю, что № 1 действительно трудно рассуждать без всего кода.Поэтому я вставлю полный код компонента ниже.Второй, я надеюсь, немного более концептуален / его легко понять, не играя с ним.

Кто-нибудь может придумать хороший способ установить местоположение центра круга?Я обеспокоен тем, что требуется постоянное обновление левого / верхнего положения круга в зависимости от его диаметра (left: location.x - diameter._value / 2), что избавит меня от всех преимуществ производительности Animated, насколько я понимаю.Есть идеи получше?

Вот полный код компонента:

import React from 'react';
import { TouchableHighlight, Animated } from 'react-native';
import { Dimensions } from 'react-native';

const colors = ['white', 'black', 'green', 'blue', 'red', 'pink'];

const color = index => colors[index % colors.length];

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

    this.state = {
      colorIndex: 0,
      location: { x: 0, y: 0 },
      diameter: new Animated.Value(0)
    };
  }

  triggerSwipe(event) {
    this.setState({ location: { x: event.nativeEvent.locationX, y: event.nativeEvent.locationY } });

    Animated.timing(
      this.state.diameter,
      { toValue: Dimensions.get('window').height * 2, duration: 500 },
    ).start(() => {
      this.state.diameter.setValue(0);
      this.setState({ colorIndex: this.state.colorIndex + 1 });
    });
  }

  render() {
    const { colorIndex, diameter, location } = this.state;

    const circleStyles = {
      backgroundColor: color(colorIndex + 1),
      width: diameter,
      height: diameter,
      borderRadius: diameter,
      position: 'absolute',
      zIndex: 2,
      left: location.x,
      top: location.y
    };

    return (
      <TouchableHighlight
        style={ {
          flex: 1,
          width: '100%',
          height: '100%',
          zIndex: 1,
          backgroundColor: color(colorIndex)
        } }
        onPress={ (event) => this.triggerSwipe(event) }
      >
        <Animated.View
          style={ circleStyles }
        />
      </TouchableHighlight>
    );
  }
}

export default ColorScape;

Вот текущая функциональность (в симуляторе iPhone X):

enter image description here

1 Ответ

0 голосов
/ 12 сентября 2018

Если вы хотите, чтобы ваш круг расширялся от точки щелчка, я бы рекомендовал использовать transform: scale() вместо анимации свойств ширины / высоты. Таким образом, вам нужно анимировать только одно свойство.

Вам все еще нужно будет центрировать свой круг. Допустим, вы установили ширину / высоту 100 пикселей. Теперь вы установили transform: scale(0) в качестве исходного размера и можете увеличить свой круг до 1, если хотите, чтобы он занимал весь экран. Вы можете играть с математикой, чтобы получить правильное время / чувство.

При таком подходе вы по-прежнему будете иметь ту же проблему увеличения круга слева вверху. Это потому, что вы разместили его там. сверху / слева относительно родительского контейнера. Теперь вам нужно центрировать свой круг относительно себя. Это означает, что вам нужно будет добавить еще одно свойство transform. transform: translateX(-50%)translateY(-50%). Это всегда будет центрировать ваш круг относительно его центральной позиции.

Начальное преобразование: transform: translateX(-50%)translateY(-50%)scale(0) Увеличенное преобразование: transform: translateX(-50%)translateY(-50%)scale(x), где x настолько большой, насколько вы хотите, чтобы круг получился.

...