更改无限动画的持续时间
Change duration in an infinite animation
我尝试制作一个无限循环的脉冲动画视图。以下视图实现了该动画。但我想在动画时更新动画持续时间。实际上它不会更新循环动画。向 useEffect 依赖项添加持续时间无法正常工作,因为它会刷新当前的动画圆圈。
喜欢这个 (Source) :
这是我当前的代码:
const LoopPulseView = (props: {duration: number;}) => {
const nbPulse = 6;
const [pulses, setPulses] = useState([] as any);
const [duration, setDuration] = useState(props.duration);
const [delay] = useState(duration / nbPulse);
useEffect(() => {
setDuration(props.duration);
}, [props.duration]);
const scaleOut = {
0: {
opacity: 1,
scale: 1,
},
1: {
opacity: 0,
scale: 1.5,
},
};
useEffect(() => {
const newPulses = [];
for (let p = 0; p < nbPulse; p++) {
const view = (
<Animatable.View
key={p}
duration={duration}
delay={delay * p}
style={[styles.pulse, pulseStyle]}
animation={scaleOut}
iterationCount={'infinite'}
useNativeDriver={true}
/>
);
newPulses.push(view);
}
setPulses(newPulses);
}, []);
return (
<View style={containerStyle}>
<View style={pulseWrapperStyle}>
{pulses.map((pulse: any) => {
return pulse;
})}
</View>
</View>
);
};
export default LoopPulseView;
您不能更改 Animatable.View 的道具,因为它会触发组件的渲染。
您不能替换所有的Animatable.View,因为它也会呈现您的组件。
解决方案是创建一个动画数组,然后逐渐增加动画数量和替换旧的。
我可以举个例子。
import React, { useState, useEffect } from 'react';
import {
View,
StyleSheet,
Button
} from 'react-native';
import * as Animatable from 'react-native-animatable';
const scaleOut = {
0: {
opacity: 1,
scale: 1,
},
1: {
opacity: 0,
scale: 1.5,
},
};
function Pulse({ duration }) {
return (
<Animatable.View
duration={duration}
animation={scaleOut}
useNativeDriver={true}
>
<View
style={[styles.pulse]}
>
</View>
</Animatable.View>
)
}
function App() {
const [pulses, setPulses] = useState([]);
const [nbPulse, setNbPulse] = useState(3);
const [duration, setDuration] = useState(3000);
useEffect(() => {
setDelay(duration / nbPulse);
}, [duration, nbPulse])
const [delay, setDelay] = useState(duration / nbPulse);
useEffect(() => {
const interval = setInterval(() => {
setPulses((prevState) => {
// create a new pulse
let pulse = {
id: String(Date.now()),
duration: duration
}
let newState = [...prevState];
// remove the first object when the limite of the length's array is reached
if (newState.length >= nbPulse) {
newState.splice(0, newState.length - nbPulse);
}
// increase the size of the array
newState.push(pulse);
return (newState);
});
}, delay);
return () => {
clearInterval(interval)
};
}, [delay]) // create a new intervale when delay is change
return (
<View
style={{
width: "100%",
flex: 1
}}>
<Button
onPress={() => { setNbPulse(nbPulse + 1) }}
title="more pulse"
color="#841584"
/>
<Button
onPress={() => {
if (nbPulse > 1) {
setNbPulse(nbPulse - 1)
}
}}
title="less pulse"
color="#841584"
/>
<Button
onPress={() => {
setDuration(duration + 1000)
}}
title="pulse live increase"
color="#841584"
/>
<Button
onPress={() => {
if (duration > 1000) {
setDuration(duration - 1000)
}
}}
title="pulse live decrease"
color="#841584"
/>
{pulses.map((item) => (
<Pulse
key={item.id} // key to avoid rerender
id={item.id}
duration={item.duration} />
))}
</View>
);
}
const styles = StyleSheet.create({
pulse: {
backgroundColor: "red",
position: 'absolute',
top: 100,
left: 100,
height: 200,
width: 200,
borderRadius: 200
}
});
export default App;
我尝试制作一个无限循环的脉冲动画视图。以下视图实现了该动画。但我想在动画时更新动画持续时间。实际上它不会更新循环动画。向 useEffect 依赖项添加持续时间无法正常工作,因为它会刷新当前的动画圆圈。
喜欢这个 (Source) :
这是我当前的代码:
const LoopPulseView = (props: {duration: number;}) => {
const nbPulse = 6;
const [pulses, setPulses] = useState([] as any);
const [duration, setDuration] = useState(props.duration);
const [delay] = useState(duration / nbPulse);
useEffect(() => {
setDuration(props.duration);
}, [props.duration]);
const scaleOut = {
0: {
opacity: 1,
scale: 1,
},
1: {
opacity: 0,
scale: 1.5,
},
};
useEffect(() => {
const newPulses = [];
for (let p = 0; p < nbPulse; p++) {
const view = (
<Animatable.View
key={p}
duration={duration}
delay={delay * p}
style={[styles.pulse, pulseStyle]}
animation={scaleOut}
iterationCount={'infinite'}
useNativeDriver={true}
/>
);
newPulses.push(view);
}
setPulses(newPulses);
}, []);
return (
<View style={containerStyle}>
<View style={pulseWrapperStyle}>
{pulses.map((pulse: any) => {
return pulse;
})}
</View>
</View>
);
};
export default LoopPulseView;
您不能更改 Animatable.View 的道具,因为它会触发组件的渲染。
您不能替换所有的Animatable.View,因为它也会呈现您的组件。
解决方案是创建一个动画数组,然后逐渐增加动画数量和替换旧的。
我可以举个例子。
import React, { useState, useEffect } from 'react';
import {
View,
StyleSheet,
Button
} from 'react-native';
import * as Animatable from 'react-native-animatable';
const scaleOut = {
0: {
opacity: 1,
scale: 1,
},
1: {
opacity: 0,
scale: 1.5,
},
};
function Pulse({ duration }) {
return (
<Animatable.View
duration={duration}
animation={scaleOut}
useNativeDriver={true}
>
<View
style={[styles.pulse]}
>
</View>
</Animatable.View>
)
}
function App() {
const [pulses, setPulses] = useState([]);
const [nbPulse, setNbPulse] = useState(3);
const [duration, setDuration] = useState(3000);
useEffect(() => {
setDelay(duration / nbPulse);
}, [duration, nbPulse])
const [delay, setDelay] = useState(duration / nbPulse);
useEffect(() => {
const interval = setInterval(() => {
setPulses((prevState) => {
// create a new pulse
let pulse = {
id: String(Date.now()),
duration: duration
}
let newState = [...prevState];
// remove the first object when the limite of the length's array is reached
if (newState.length >= nbPulse) {
newState.splice(0, newState.length - nbPulse);
}
// increase the size of the array
newState.push(pulse);
return (newState);
});
}, delay);
return () => {
clearInterval(interval)
};
}, [delay]) // create a new intervale when delay is change
return (
<View
style={{
width: "100%",
flex: 1
}}>
<Button
onPress={() => { setNbPulse(nbPulse + 1) }}
title="more pulse"
color="#841584"
/>
<Button
onPress={() => {
if (nbPulse > 1) {
setNbPulse(nbPulse - 1)
}
}}
title="less pulse"
color="#841584"
/>
<Button
onPress={() => {
setDuration(duration + 1000)
}}
title="pulse live increase"
color="#841584"
/>
<Button
onPress={() => {
if (duration > 1000) {
setDuration(duration - 1000)
}
}}
title="pulse live decrease"
color="#841584"
/>
{pulses.map((item) => (
<Pulse
key={item.id} // key to avoid rerender
id={item.id}
duration={item.duration} />
))}
</View>
);
}
const styles = StyleSheet.create({
pulse: {
backgroundColor: "red",
position: 'absolute',
top: 100,
left: 100,
height: 200,
width: 200,
borderRadius: 200
}
});
export default App;