Javascript 反应本机动画-展开以按下键为中心的圆圈
我正在尝试使用React Native上的动画创建一个组件,其中一个圆从压力机的点扩展到整个屏幕 这个想法是,基本上有一个旋转木马的颜色,说:Javascript 反应本机动画-展开以按下键为中心的圆圈,javascript,css,react-native,animation,react-animated,Javascript,Css,React Native,Animation,React Animated,我正在尝试使用React Native上的动画创建一个组件,其中一个圆从压力机的点扩展到整个屏幕 这个想法是,基本上有一个旋转木马的颜色,说: const colors = ['white', 'black', 'green', 'blue', 'red', 'pink']; 首先以颜色0作为背景,然后,当按下屏幕时,颜色1的圆圈从按下点开始展开(从无到有),并占据整个屏幕。此时,动画完成后,colorIndex将递增,动画圆圈同时被擦除,因此,我们无缝地移动到下一种颜色,即现在的背景。(例如
const colors = ['white', 'black', 'green', 'blue', 'red', 'pink'];
首先以颜色0作为背景,然后,当按下屏幕时,颜色1的圆圈从按下点开始展开(从无到有),并占据整个屏幕。此时,动画完成后,colorIndex
将递增,动画圆圈同时被擦除,因此,我们无缝地移动到下一种颜色,即现在的背景。(例如,我们现在使用“黑色”作为背景色)
然后,当您再次按下时,该过程会重复,扩展一个“绿色”圆圈以填充屏幕,然后将绿色更新为背景色,等等
(要澄清我在动画中寻找的内容,请查看(减去图标等))
我正在用动画和如下代码来尝试这一点,在按下主背景组件(一个可触摸的突出显示)时调用:
然后,在渲染
函数中,我将绝对
的左
和顶
设置为与位置相等,并将宽度
和高度
设置为等于直径
,以及边界半径
(diameter/2.0
不起作用,因为diameter
是动画对象,而不是数字)
这里有两个问题我似乎无法理解(这两个问题都可以在问题底部的GIF中看到):
left:location.x-diameter.\u 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;
从“React”导入React;
从“react native”导入{TouchableHighlight,动画};
从“react native”导入{Dimensions};
常量颜色=[“白色”、“黑色”、“绿色”、“蓝色”、“红色”、“粉色”];
const color=index=>colors[index%colors.length];
类ColorScape扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
颜色索引:0,
位置:{x:0,y:0},
直径:新动画。值(0)
};
}
触发滑动(事件){
this.setState({location:{x:event.nativeEvent.locationX,y:event.nativeEvent.locationY}});
时间(
这个,州,直径,
{toValue:Dimensions.get('window')。高度*2,持续时间:500},
).start(()=>{
此.state.diameter.setValue(0);
this.setState({colorIndex:this.state.colorIndex+1});
});
}
render(){
const{colorIndex,diameter,location}=this.state;
常数圈样式={
背景颜色:颜色(颜色索引+1),
宽度:直径,
高度:直径,
边界半径:直径,
位置:'绝对',
zIndex:2,
左:location.x,
上图:地点
};
返回(
this.triggerSwipe(事件)}
>
如果您希望圆从单击点开始展开,我建议使用transform:scale()
而不是设置宽度/高度属性的动画。这样您只需设置一个属性的动画
您仍然需要将圆居中。假设您将宽度/高度设置为100px。现在您将transform:scale(0)
设置为初始大小,如果您愿意,您可以将圆缩放到1以上,因此需要全屏显示。您可以玩数学游戏以获得正确的计时/感觉
使用这种方法,您仍然会遇到从左上角开始放大圆的问题。这是因为您已将其定位在那里。左上角相对于父容器。您现在需要将圆相对于自身居中。这意味着您需要添加另一个transform
属性。transform:translateeX(-50%)translateY(-50%)
。这将始终使圆相对于其中心位置居中
开始转换:transform:translateX(-50%)translateY(-50%)比例(0)
放大的变换:transform:translateX(-50%)translateY(-50%)scale(x)
其中x
是您希望圆得到的大小。如果您希望圆从单击点开始展开,我建议使用transform:scale()
而不是设置宽度/高度属性的动画。这样,您只需设置一个属性的动画
您仍然需要将圆居中。假设您将宽度/高度设置为100px。现在您将transform:scale(0)
设置为初始大小,如果您愿意,您可以将圆缩放到1以上,因此需要全屏显示。您可以玩数学游戏以获得正确的计时/感觉
使用这种方法,您仍然会遇到从左上角开始放大圆的问题。这是因为您已将其定位在那里。左上角相对于父容器。您现在需要将圆相对于自身居中。这意味着您将
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;