1. RN动画类型
(1) Animated API:
包括Animated.View、Animated.Text等组件,支持基本的属性动画,如平移、旋转、缩放、透明度等。同时也可以实现交互式动画,如响应手势、触摸等。
import React, { useState } from 'react';
import { StyleSheet, View, Animated } from 'react-native';
const App = () => {
const [animation] = useState(new Animated.Value(0));
const startAnimation = () => {
Animated.timing(animation, {
toValue: 1,
duration: 1000,
useNativeDriver: true,
}).start();
};
return (
<View style={styles.container}>
<Animated.View
style={[
styles.box,
{
opacity: animation,
transform: [
{
translateY: animation.interpolate({
inputRange: [0, 1],
outputRange: [200, 0],
}),
},
],
},
]}
/>
<Button title="Start Animation" onPress={startAnimation} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
box: {
width: 100,
height: 100,
backgroundColor: 'red',
},
});
export default App;
这个组件实现了一个简单的动画效果,当用户按下 "Start Animation" 按钮时,一个红色的方块从屏幕底部淡入并向上滑动到屏幕正中央。
这个动画是通过控制 Animated View 组件的不透明度和 translateY 属性来实现的。在动画开始时,Animated View 的 opacity 是 0,translateY 是 200。通过使用 Animated.timing 方法更新 Animated.View 的 opacity 和 translateY 属性,使得这两个属性都会随着时间的推移而变化,创建了一个淡入并滑动的动画效果。
(2) LayoutAnimation:
通过声明式的方式实现布局动画,例如在组件添加或删除时自动调整其位置和大小,并提供了多个预设的动画效果,如easeInEaseOut、linear等。
import React, { useState } from 'react';
import { StyleSheet, View, Text, LayoutAnimation, TouchableOpacity } from 'react-native';
const App = () => {
const [showText, setShowText] = useState(true);
const toggleText = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setShowText(!showText);
};
return (
<View style={styles.container}>
<TouchableOpacity onPress={toggleText}>
<Text>{showText ? 'Hide Text' : 'Show Text'}</Text>
</TouchableOpacity>
{showText && <Text style={styles.text}>This is a sample text.</Text>}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
text: {
fontSize: 20,
fontWeight: 'bold',
},
});
export default App;
这个组件实现了一个简单的文本显示/隐藏效果。当用户点击 "Hide Text" 按钮时,文本会消失;当用户点击 "Show Text" 按钮时,文本会重新出现。
在这个组件中,LayoutAnimation API 用来控制组件的动画效果。在 toggleText 函数中,我们调用 LayoutAnimation.configureNext 方法,并传入一个配置对象,使得在组件状态改变时,视图可以以预定义的方式发生变化。这里使用的是 LayoutAnimation.Presets.easeInEaseOut 预设值,它提供了一种平滑过渡的效果,让组件的显示和隐藏看起来更加自然流畅。
点击 "Hide Text" 和 "Show Text" 按钮时,我们通过更新组件的状态来触发动画效果。具体地说,当用户点击按钮时,我们会更新 showText 状态的值,从而导致组件的重新渲染。如果 showText 的值为 true,则渲染 <Text> 组件并显示文本内容;否则,不渲染任何东西,即使之前已经有文本显示出来了。
总之,这个组件利用 LayoutAnimation 和状态管理来实现了一个简单的文本显示/隐藏效果,使得用户可以轻松地控制组件的显示和隐藏。
(3) Reanimated:
一个高性能的动画库,提供更丰富和复杂的动画类型和计算方式,例如支持使用手势控制动画、支持更精细的动画控制等。
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';
import Animated, { useAnimatedGestureHandler, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
import { PanGestureHandler } from 'react-native-gesture-handler';
const App = () => {
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const onGestureEvent = useAnimatedGestureHandler({
onStart: (_, ctx) => {
ctx.offsetX = translateX.value;
ctx.offsetY = translateY.value;
},
onActive: (event, ctx) => {
translateX.value = ctx.offsetX + event.translationX;
translateY.value = ctx.offsetY + event.translationY;
},
onEnd: () => {
translateX.value = withSpring(0);
translateY.value = withSpring(0);
},
});
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ translateX: translateX.value },
{ translateY: translateY.value },
],
}));
return (
<View style={styles.container}>
<PanGestureHandler onGestureEvent={onGestureEvent}>
<Animated.View style={[styles.box, animatedStyle]} />
</PanGestureHandler>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
box: {
width: 100,
height: 100,
backgroundColor: 'red',
},
});
export default App;
这个组件实现了一个简单的拖动效果。当用户在屏幕上用手指拖动红色方块时,方块会跟随手指移动,并且在释放手指后会回到原位置。
在这个组件中,我们使用了 react-native-reanimated 和 react-native-gesture-handler 库来实现动画和手势操作。首先,我们通过 useSharedValue 钩子创建了两个共享值 translateX 和 translateY,它们分别用于记录方块在 x、y 轴上的偏移量。然后,我们使用 useAnimatedGestureHandler 钩子来创建了一个手势事件处理函数,在这个函数中,我们对手指的开始、移动和结束事件进行了处理,更新了 translateX 和 translateY 的值以实现方块的拖动效果。最后,我们使用 useAnimatedStyle 钩子来创建一个动画样式对象 animatedStyle,其中包含了 translateX 和 translateY 的变化,将其应用到 Animated.View 组件的 style 属性上,从而实现了方块的位移效果。
总之,这个组件利用 react-native-reanimated 和 react-native-gesture-handler 库来实现了一个简单的拖动效果,可以帮助用户轻松地移动组件。
2.Flutter动画类型
(1) Tween Animation:
基于值的插值动画,在指定时间内从一个数值变化到另一个数值,例如颜色渐变、大小变化、位置变化等。
class TweenAnimation extends StatefulWidget {
@override
_TweenAnimationState createState() => _TweenAnimationState();
}
class _TweenAnimationState extends State<TweenAnimation> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<Color> _colorAnimation;
Animation<double> _sizeAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
_colorAnimation = ColorTween(begin: Colors.red, end: Colors.blue).animate(_controller);
_sizeAnimation = Tween<double>(begin: 100, end: 200).animate(_controller);
_controller.forward();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget child) {
return Container(
color: _colorAnimation.value,
width: _sizeAnimation.value,
height: _sizeAnimation.value,
);
},
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
实现了一个简单的值插值动画,使用Tween对象指定数值的变化范围,并将其应用到AnimationController上,然后监听AnimationController的变化,并在builder函数中将Animation对象的值应用到Container组件的宽度和高度上,以实现渐变颜色的效果。
(2) Physics-based Animation:
基于真实物理规律的动画,例如重力、摩擦等,可以模拟弹簧振动、滑动摩擦等物理效应。
class PhysicsBasedAnimation extends StatefulWidget {
@override
_PhysicsBasedAnimationState createState() => _PhysicsBasedAnimationState();
}
class _PhysicsBasedAnimationState extends State<PhysicsBasedAnimation> with TickerProviderStateMixin {
AnimationController _controller;
Animation<Offset> _offsetAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_offsetAnimation = Tween<Offset>(begin: Offset.zero, end: const Offset(1.0, 0.0)).animate(
CurvedAnimation(parent: _controller, curve: Curves.elasticInOut));
_controller.forward();
}
@override
Widget build(BuildContext context) {
return SlideTransition(
position: _offsetAnimation,
child: Container(
color: Colors.red,
width: 100,
height: 100,
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
实现了一个基于真实物理规律的弹性运动动画。通过CurvedAnimation对象和addListener方法来监听AnimationController的变化,并在UI上使用Transform.translate实现位移动画,将偏移量与弹性曲线结合起来,以模拟物理效应。
(3) Staggered Animation:
异步动画,可以让多个动画同时进行并按不同时间间隔排列,例如旋转菜单、分散动画等。
class StaggeredAnimation extends StatefulWidget {
@override
_StaggeredAnimationState createState() => _StaggeredAnimationState();
}
class _StaggeredAnimationState extends State<StaggeredAnimation> with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animationOne;
Animation<double> _animationTwo;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_animationOne = Tween<double>(begin: 0, end: 100).animate(
CurvedAnimation(parent: _controller, curve: Interval(0, 0.5, curve: Curves.easeOut)));
_animationTwo = Tween<double>(begin: 0, end: 100).animate(
CurvedAnimation(parent: _controller, curve: Interval(0.5, 1, curve: Curves.easeOut)));
_controller.forward();
}
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
AnimatedBuilder(
animation: _animationOne,
builder: (BuildContext context, Widget child) {
return SizedBox(
width: _animationOne.value,
height: 100,
child: Container(color: Colors.red),
);
},
),
AnimatedBuilder(
animation: _animationTwo,
builder: (BuildContext context, Widget child) {
return SizedBox(
width: _animationTwo.value,
height: 100,
child: Container(color: Colors.blue),
);
},
),
],
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
实现了一个异步动画,可以让多个动画同时进行并按不同时间间隔排列。通过AnimationController.repeat()方法重复播放动画,并在StaggeredAnimationCard组件中定义了四个Tween对象,分别控制四个Padding的变化范围,然后通过CurvedAnimation对象和Interval构造函数将它们组合起来,形成一系列交错动画效果。
(4) Implicit Animation:
隐式动画,由Flutter框架自动处理,例如Widget的子节点发生变化时,框架会自动处理新旧节点之间的动画过渡。
class ImplicitAnimation extends StatefulWidget {
@override
_ImplicitAnimationState createState() => _ImplicitAnimationState();
}
class _ImplicitAnimationState extends State<ImplicitAnimation> {
bool _isAnimated = false;
void _toggleAnimation() {
setState(() {
_isAnimated = !_isAnimated;
});
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _toggleAnimation,
child: Center(
child: AnimatedContainer(
duration: const Duration(seconds: 1),
width: _isAnimated ? 200.0 : 100.0,
height: _isAnimated ? 100.0 : 200.0,
color: _isAnimated ? Colors.blue : Colors.red,
alignment: _isAnimated ? Alignment.centerLeft : Alignment.centerRight,
child: Text(
'Click me',
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
),
),
);
}
}
在这个示例中,当用户点击屏幕时,AnimatedContainer的大小、颜色、对齐方式等会发生变化,Flutter框架会自动处理新旧状态之间的动画过渡。我们只需要设置AnimatedContainer的duration和变化后的值即可。
3. Android原生
(1)View Animation:
基于 View 对象进行的动画处理,可以对 View 进行平移、旋转、缩放等操作,并提供了多种插值器,如加速插值器、减速插值器等。
Animation animation = new TranslateAnimation(0f, 500f, 0f, 500f);
animation.setDuration(1000);
view.startAnimation(animation);
这个示例代码通过 TranslateAnimation 类创建了一个平移动画,使目标 View 沿着 x 轴和 y 轴方向移动 500px。其中 view 是要进行动画处理的 View 对象,第一个参数 "0f" 和第二个参数 "500f" 表示 x 轴方向上起始位置和结束位置,第三个参数 "0f" 和第四个参数 "500f" 表示 y 轴方向上起始位置和结束位置。最后,设置动画的持续时间为 1000ms,并启动动画。
这个示例代码实现了一个简单的斜向平移效果,当动画开始时,目标 View 从左上角(0,0)位置沿着对角线移动到右下角(500,500)位置,持续时间为 1 秒。虽然 View Animation 功能比较有限,但它仍然适用于一些简单的动画效果。
(2)Property Animation:
针对任意对象的属性进行动画处理,例如数值、颜色等,支持更丰富和灵活的动画效果。
ObjectAnimator animatorX = ObjectAnimator.ofFloat(view, "translationX", 0f, 500f);
animatorX.setDuration(1000);
animatorX.start();
这个示例代码通过 ObjectAnimator 对象创建了一个沿着 x 轴平移的属性动画,使目标 View 从原始位置移动到 x 坐标为 500 的位置。其中 view 是要进行动画处理的 View 对象,"translationX" 表示要操作的属性名称,第二个参数 "0f" 是起始值,第三个参数 "500f" 是结束值,表示移动距离为 500px。最后,设置动画的持续时间为 1000ms,并启动动画。
这个示例代码实现了一个简单的水平移动效果,当动画开始时,目标 View 从屏幕左侧移动到屏幕右侧,持续时间为 1 秒。相对于 View Animation,Property Animation 支持更丰富和灵活的动画效果。
(3) Drawable Animation:
基于图片序列的动画,通过逐帧播放图片来实现动态效果,例如帧动画、翻页动画等。
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<item android:drawable="@drawable/frame1" android:duration="200"/>
<item android:drawable="@drawable/frame2" android:duration="200"/>
<item android:drawable="@drawable/frame3" android:duration="200"/>
</animation-list>
这个示例代码通过 animation-list 定义了一个帧动画,每个 item 表示一帧动画。在播放时,系统会逐帧地显示所有 drawable 对象,形成动态的效果。其中 android:drawable 属性指定了每一帧要显示的 drawable 对象,android:duration 属性指定了每一帧的持续时间。
这个示例代码实现了一个简单的帧动画,包含三个帧,每个帧持续时间为 200ms。当播放时,系统会逐帧地显示这三幅图片,形成连续动态效果。Drawable Animation 常用于需要逐帧动态变化的场景,如帧动画、翻页动画等。
4.CSS动画
(1) Transition:
CSS3中内置的过渡动画,可以定义两个状态之间的动画过渡效果,例如opacity、transform等属性。
div {
opacity: 0;
transition: opacity 1s ease-in-out;
}
div:hover {
opacity: 1;
}
当鼠标悬停在该元素上时,它会从透明度为0的状态平滑地过渡到透明度为1的状态,持续时间为1秒,并使用缓入缓出的动画函数进行渐变。
(2) Animation:
包括关键帧动画和无限循环动画,可以通过定义关键帧或使用预设动画效果来实现复杂的动画效果。
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
div {
animation-name: rotate;
animation-duration: 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
该示例定义了一个名为rotate的关键帧动画,使元素从起始状态旋转0度到最终状态旋转360度。然后将该动画应用于div元素,并设置了持续时间为2秒,动画函数为线性缓动,循环次数为无限。
(3) Transform:
可以对元素进行旋转、缩放、位移等变换操作,同时可以设置过渡动画来实现更流畅的效果。
div {
transform: scale(1);
transition: transform 0.5s ease-in-out;
}
div:hover {
transform: scale(1.2);
}
该示例定义了一个初始状态下元素的scale值为1,并设置了一个渐进过渡动画效果,持续时间为0.5秒,并使用了缓入缓出的动画函数。当鼠标悬停在该元素上时,它会从当前状态平滑地过渡到放大20%的状态。