export default class Test extends Component {
state = {
bounceValue: new Animated.Value(0),
};
render() {
return (
<Animated.Image source={require(‘./my-icon.png’)} style={{
transform: [{scale: this.state.bounceValue}]
}}/>)
}
componentDidMount() {
Animated.timing(this.state.bounceValue, {
toValue: 3,
duration: 3000,
// useNativeDriver: true 这里先注释掉,标记为注释@1
}).start()
}
}
通过查看AnimatedImplementation.js文件可以查看到动画源码,篇幅有限仅展示核心代码
所有Animated的js源码都在AnimatedImplementation.js中,本文RN版本为0.57.8.
首先看下动画的入口函数:Animated.timing
该函数定义在181行,不同RN版本对应的行数不一致,请以自己的版本为准。
const timing = function(
value: AnimatedValue | AnimatedValueXY,
config: TimingAnimationConfig,
): CompositeAnimation {
const start = function(
animatedValue: AnimatedValue | AnimatedValueXY,
configuration: TimingAnimationConfig,
callback?: ?EndCallback,
): void {
callback = _combineCallbacks(callback, configuration);
const singleValue: any = animatedValue;
const singleConfig: any = configuration;
singleValue.stopTracking();
if (configuration.toValue instanceof AnimatedNode) {
singleValue.track(
new AnimatedTracking(
singleValue,
configuration.toValue,
TimingAnimation,
singleConfig,
callback,
),
);
} else {
singleValue.animate(new TimingAnimation(singleConfig), callback);
}
};
这里的singleValue是传入的第一个参数this.state.bounceValue,为AnimatedValue类型。
这里的singleConfig是传入的第二个参数。
首先分析下第一个参数的AnimatedValue这个类型的animate方法:
animate(animation: Animation, callback: ?EndCallback): void {
let handle = null;
if (animation.__isInteraction) {
handle = InteractionManager.createInteractionHandle();
}
const previousAnimation = this._animation;
this._animation && this._animation.stop();
this._animation = animation;
animation.start(
this._value,
value => {
// Natively driven animations will never call into that callback, therefore we can always
// pass flush = true to allow the updated value to propagate to native with setNativeProps
this._updateValue(value, true /* flush */);
},
result => {
this._animation = null;
if (handle !== null) {
InteractionManager.clearInteractionHandle(handle);
}
callback && callback(result);
},
previousAnimation,
this,
);
}
该方法内部主要是为了调用传入参数animation的start方法,这个参数就是上面传过来的new TimingAnimation(singleConfig)对象。TimingAnimation的start方法如下:
start(
fromValue: number,
onUpdate: (value: number) => void,
onEnd: ?EndCallback,
previousAnimation: ?Animation,
animatedValue: AnimatedValue,
): void {
this.__active = true;
this._fromValue = fromValue;
this._onUpdate = onUpdate;
this.__onEnd = onEnd;
const start = () => {
// Animations that sometimes have 0 duration and sometimes do not
// still need to use the native driver when duration is 0 so as to
// not cause intermixed JS and native animations.
if (this._duration === 0 && !this._useNativeDriver) {
this._onUpdate(this._toValue);
this.__debouncedOnEnd({finished: true});
} else {
this._startTime = Date.now();
if (this._useNativeDriver) {
this.__startNativeAnimation(animatedValue);
} else {
this._animationFrame = requestAnimationFrame(
this.onUpdate.bind(this),
);
}
}
};
if (this._delay) {
this._timeout = setTimeout(start, this._delay);
} else {
start();
}
}
这里出现了分支,当注释@1打开时,_useNativeDriver为true,动画的执行方式将交由原生端,不再走下边的js端。
原生端实现:
可以看到js调用了__startNativeAnimation方法,我们看下__startNativeAnimation
__startNativeAnimation(animatedValue: AnimatedValue): void {
animatedValue.__makeNative();
this.__nativeId = NativeAnimatedHelper.generateNewAnimationId();
NativeAnimatedHelper.API.startAnimatingNode(
this.__nativeId,
animatedValue.__getNativeTag(),
this.__getNativeAnimationConfig(),
this.__debouncedOnEnd.bind(this),
);
}
我们着重看下这个方法NativeAnimatedHelper.API.startAnimatingNode:
startAnimatingNode: function(
animationId: ?number,
nodeTag: ?number,
config: Object,
endCallback: EndCallback,
): void {
assertNativeAnimatedModule();
NativeAnimatedModule.startAnimatingNode(
animationId,
nodeTag,
config,
endCallback,
);
},
我们可以看到内部执行了NativeAnimatedModule.startAnimatingNode,熟悉Android开发的同学可能知道这是调用了Android端的方法,那我们去Android端看下这个NativeAnimatedModule
这里边包含了Android与JS动画交互的方法,有兴趣的同学可以看下这个文件,该文件在这个包下
package com.facebook.react.animated;
我们看下startAnimatingNode方法:
@ReactMethod
public void startAnimatingNode(
final int animationId,
final int animatedNodeTag,
final ReadableMap animationConfig,
final Callback endCallback) {
mOperations.add(new UIThreadOperation() {
@Override
最后
给大家分享一份移动架构大纲,包含了移动架构师需要掌握的所有的技术体系,大家可以对比一下自己不足或者欠缺的地方有方向的去学习提升;
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
int animationId,
final int animatedNodeTag,
final ReadableMap animationConfig,
final Callback endCallback) {
mOperations.add(new UIThreadOperation() {
@Override
最后
给大家分享一份移动架构大纲,包含了移动架构师需要掌握的所有的技术体系,大家可以对比一下自己不足或者欠缺的地方有方向的去学习提升;
[外链图片转存中…(img-aBPuTiWY-1715746138035)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!