Я пытаюсь создать компонент с помощью Animated on React Native, где круг расширяется от точки нажатия, чтобы охватить весь экран.
Идея состоит в том, что, по сути, это карусель цветов, скажем:
const colors = ['white', 'black', 'green', 'blue', 'red', 'pink'];
Вы начинаете с цвета 0 в качестве фона, а затем, когда вы нажимаете на экран, круг цвета 1 расширяется (из ничего) от точки нажатия и занимает весь экран. В этот момент, когда анимация завершена, colorIndex
увеличивается, и анимированный круг одновременно стирается, так что мы плавно перешли к следующему цвету, который теперь является фоном. (Например, сейчас мы используем «черный» в качестве цвета фона).
Затем, когда вы снова нажимаете, процесс повторяется, расширяя круг «зеленого» для заполнения экрана, затем обновляя зеленый цвет, чтобы он стал цветом фона, и т. д.
(Чтобы уточнить, что я ищу в анимации, проверьте этот GIF out (без значков и т. д.)).
Я пробую это с 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
ly компонента круга равными положению, и я устанавливаю width
и height
равными diameter
, а также borderRadius
(diameter / 2.0
не будет работать, потому что diameter
является Анимированный объект, а не число).
Здесь возникают две проблемы, которые я не могу понять (оба видны в GIF, включенном в нижней части этого вопроса):
- Перед каждой анимацией появляется черная вспышка. Он охватывает весь компонент TouchableHighlight. И всегда черный. Какой бы цвет я ни был. В компоненте нет хардкодного черного (!).
- Местоположение определяет край круга (или, точнее, квадрат, в который он вписан), а не центр. Я хочу, чтобы он определял центр круга, чтобы круг расширялся наружу от моего пресса.
Я предполагаю, что № 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):