先看一个示例
class Playground extends React.Component {
constructor(props) {
super(props);
this.state = {
bounceValue: new Animated.Value(0),
};
}
render() {
return (
<Animated.Image // Base: Image, Text, View
source={{uri: 'http://i.imgur.com/XMKOH81.jpg'}}
style={{
flex: 1,
transform: [ // `transform` is an ordered array
{scale: this.state.bounceValue}, // Map `bounceValue` to `scale`
]
}}
/>
);
}
componentDidMount() {
this.state.bounceValue.setValue(1.5); // Start large
Animated.spring( // Base: spring, decay, timing
this.state.bounceValue, // Animate `bounceValue`
{
toValue: 0.8, // Animate to smaller size
friction: 1, // Bouncier spring
}
).start(); // Start the animation
}
}
动画是从 Animated.spring开始的
找到对应实现
var spring = function(
value: AnimatedValue | AnimatedValueXY,
config: SpringAnimationConfig,
): CompositeAnimation {
return maybeVectorAnim(value, config, spring) || {
start: function(callback?: ?EndCallback): void {
callback = _combineCallbacks(callback, config);
var singleValue: any = value;
var singleConfig: any = config;
singleValue.stopTracking();
if (config.toValue instanceof Animated) {
singleValue.track(new AnimatedTracking(
singleValue,
config.toValue,
SpringAnimation,
singleConfig,
callback
));
} else {
singleValue.animate(new SpringAnimation(singleConfig), callback);
}
},
stop: function(): void {
value.stopAnimation();
},
};
};
看来目标值存在singleValue,然后结束值和动画实现放在singleConfig
这里start函数都直接有的
最重要的是singleValue.animate(new SpringAnimation(singleConfig), callback);
singlevalue是一个Animated.Value 类型。调用这里面的animate方法。然后传入的类型是SpringAnimation。
Animated.Value
下面研究Animated.Value类型(这个类型我找不到) 但是从函数定义上来来说 是AnimatedValue类型
下面是value 的实现
animate(animation: Animation, callback: ?EndCallback): void {
var handle = null;
if (animation.__isInteraction) {
handle = InteractionManager.createInteractionHandle();
}
var 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
);
}
看来是调用
SpringAnimation的start方法给了一个初始值 然后穿了两个函数。
主要是的是把_updateValue 也传了进去。
先把_updateValue放在这里。
_updateValue(value: number, flush: bool): void {
this._value = value;
if (flush) {
_flush(this);
}
for (var key in this._listeners) {
this._listeners[key]({value: this.__getValue()});
}
}
class SpringAnimation extends Animation
SpringAnimation 在构造的时候就知道动画结束值和动画的持续时间
constructor(
config: SpringAnimationConfigSingle,
) {
super();
this._overshootClamping = withDefault(config.overshootClamping, false);
this._restDisplacementThreshold = withDefault(config.restDisplacementThreshold, 0.001);
this._restSpeedThreshold = withDefault(config.restSpeedThreshold, 0.001);
this._initialVelocity = config.velocity;
this._lastVelocity = withDefault(config.velocity, 0);
this._toValue = config.toValue;
this._useNativeDriver = shouldUseNativeDriver(config);
this.__isInteraction = config.isInteraction !== undefined ? config.isInteraction : true;
结束值在this._toValue里面
start函数
start(
fromValue: number,
onUpdate: (value: number) => void,
onEnd: ?EndCallback,
previousAnimation: ?Animation,
animatedValue: AnimatedValue
): void {
this.__active = true;
this._startPosition = fromValue;
this._lastPosition = this._startPosition;
this._onUpdate = onUpdate;
this.__onEnd = onEnd;
this._lastTime = Date.now();
if (previousAnimation instanceof SpringAnimation) {
var internalState = previousAnimation.getInternalState();
this._lastPosition = internalState.lastPosition;
this._lastVelocity = internalState.lastVelocity;
this._lastTime = internalState.lastTime;
}
if (this._initialVelocity !== undefined &&
this._initialVelocity !== null) {
this._lastVelocity = this._initialVelocity;
}
if (this._useNativeDriver) {
this.__startNativeAnimation(animatedValue);
} else {
this.onUpdate();
}
}
start里面有个重点
if (this._useNativeDriver) {
this.__startNativeAnimation(animatedValue);
} else {
this.onUpdate();
}
非native
这里会区分是本地动画还是自己的动画。
先分析onUpdate
opUpdate会计算出当前时间动画的值
然后调用this._onUpdate
这个就是AnimatedValue传进来的回调函数。执行的是AnimatedValue的 this._updateValue(value, true /* flush */);
这个函数会大flush标记 和 通知监听者 todo
看来SpringAnimation只是用于计算动画的当前的值。并没有涉及到原理性的东西。
native
下面看一下native的实现
__startNativeAnimation
__startNativeAnimation(animatedValue: AnimatedValue): void {
animatedValue.__makeNative();
this.__nativeId = NativeAnimatedHelper.generateNewAnimationId();
NativeAnimatedAPI.startAnimatingNode(
this.__nativeId,
animatedValue.__getNativeTag(),
this.__getNativeAnimationConfig(),
this.__debouncedOnEnd.bind(this)
);
}
现在要去看NativeAnimatedHelper.js
下面就是要做分平台处理了
ios RCTNativeAnimatedModule.m
Android NativeAnimatedModule.java
RCTNativeAnimatedModule.m
这个类对外提供接口
RCT_EXPORT_METHOD(startAnimatingNode:(nonnull NSNumber *)animationId
nodeTag:(nonnull NSNumber *)nodeTag
config:(NSDictionary