mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Execute Animated.js declarative animation on UIThread on Android.
Summary:This is the first from the series of PRs I'm going to be sending shorty that would let Animated.js animations to run off the JS thread (for Android only). This PR introduce a new native module that will be used for offloading animations - NativeAnimatedModule. It has a simple API that allows for animated nodes management via methods like: create/drop animated node, connect/disconnect nodes, start animation of a value node, attach/detach animated from a native view. Similarly to how we handle UIManager view hierarchy updates we create a queue of animated graph operations that are then executed on the UI thread. This isolates us from problems that may be caused by concurrent updates of animated graph while UI thread is "executing" the animation. The most important class NativeAnimatedNodesManager.java implements a management interface for animated nodes graph as well as implements a graph traversal algorithm that is run for each animation frame. For each animation frame we visit animated nodes th Closes https://github.com/facebook/react-native/pull/6466 Differential Revision: D3092739 Pulled By: astreet fb-gh-sync-id: 665b49900b7367c91a93b9d8864f78fb90bb36ba shipit-source-id: 665b49900b7367c91a93b9d8864f78fb90bb36ba
This commit is contained in:
committed by
Facebook Github Bot 5
parent
bd8007300f
commit
65ccdffc8d
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.animated;
|
||||
|
||||
import com.facebook.react.bridge.JavaOnlyMap;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
||||
import com.facebook.react.uimanager.NativeViewHierarchyManager;
|
||||
import com.facebook.react.uimanager.ReactStylesDiffMap;
|
||||
import com.facebook.react.uimanager.UIImplementation;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Animated node that represents view properties. There is a special handling logic implemented for
|
||||
* the nodes of this type in {@link NativeAnimatedNodesManager} that is responsible for extracting
|
||||
* a map of updated properties, which can be then passed down to the view.
|
||||
*/
|
||||
/*package*/ class PropsAnimatedNode extends AnimatedNode {
|
||||
|
||||
/*package*/ int mConnectedViewTag = -1;
|
||||
|
||||
private final NativeAnimatedNodesManager mNativeAnimatedNodesManager;
|
||||
private final Map<String, Integer> mPropMapping;
|
||||
|
||||
PropsAnimatedNode(ReadableMap config, NativeAnimatedNodesManager nativeAnimatedNodesManager) {
|
||||
ReadableMap props = config.getMap("props");
|
||||
ReadableMapKeySetIterator iter = props.keySetIterator();
|
||||
mPropMapping = new HashMap<>();
|
||||
while (iter.hasNextKey()) {
|
||||
String propKey = iter.nextKey();
|
||||
int nodeIndex = props.getInt(propKey);
|
||||
mPropMapping.put(propKey, nodeIndex);
|
||||
}
|
||||
mNativeAnimatedNodesManager = nativeAnimatedNodesManager;
|
||||
}
|
||||
|
||||
public final void updateView(UIImplementation uiImplementation) {
|
||||
if (mConnectedViewTag == -1) {
|
||||
throw new IllegalStateException("Node has not been attached to a view");
|
||||
}
|
||||
JavaOnlyMap propsMap = new JavaOnlyMap();
|
||||
for (Map.Entry<String, Integer> entry : mPropMapping.entrySet()) {
|
||||
AnimatedNode node = mNativeAnimatedNodesManager.getNodeById(entry.getValue());
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("Mapped property node does not exists");
|
||||
} else if (node instanceof StyleAnimatedNode) {
|
||||
((StyleAnimatedNode) node).collectViewUpdates(propsMap);
|
||||
} else if (node instanceof ValueAnimatedNode) {
|
||||
propsMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).mValue);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported type of node used in property node " +
|
||||
node.getClass());
|
||||
}
|
||||
}
|
||||
// TODO: Reuse propsMap and stylesDiffMap objects - note that in subsequent animation steps
|
||||
// for a given node most of the time we will be creating the same set of props (just with
|
||||
// different values). We can take advantage on that and optimize the way we allocate property
|
||||
// maps (we also know that updating view props doesn't retain a reference to the styles object).
|
||||
uiImplementation.synchronouslyUpdateViewOnUIThread(
|
||||
mConnectedViewTag,
|
||||
new ReactStylesDiffMap(propsMap));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user