1

我正在尝试在 React Native 上使用 Animated 创建一个组件,其中一个圆圈从按下的点扩展到整个屏幕。

这个想法是本质上是一个颜色的轮播,比如说:

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函数中,我设置lefttopabsolute定位圆组件的和等于位置,我设置widthheight等于diameter,以及borderRadiusdiameter / 2.0不起作用,因为diameter是一个动画对象,而不是一个数字)。

这里有两个我似乎无法弄清楚的问题(都可以在这个问题底部的 GIF 中看到):

  1. 每个动画前都有黑色闪光。它涵盖了整个 TouchableHighlight 组件。而且它总是黑色的。不管我穿什么颜色。组件中没有硬编码的黑色 (!)。
  2. 位置决定了圆的边缘(或者更准确地说,它是在其中转录的正方形),而不是中心。我希望它确定圆心,以便圆从我的印刷机向外扩展。

我假设没有所有代码,#1 真的很难推理。所以我将在下面粘贴完整的组件代码。我希望的第二个在不玩它的情况下更具概念性/易于理解。

谁能想到一个断言圆心位置的好方法?我担心它需要根据圆的直径left: location.x - diameter._value / 2(有更好的想法吗?

这是完整的组件代码:

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 模拟器中):

在此处输入图像描述

4

1 回答 1

4

如果您希望您的圆圈从单击点开始扩展,我建议您使用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得到。

于 2018-09-12T19:27:38.870 回答