mirror of
https://github.com/status-im/react-native.git
synced 2025-01-15 20:15:11 +00:00
@build-break revert of D2217731
Differential Revision: D2702368 fb-gh-sync-id: 64f53168610c5bf5f3dc22cd7e4dd6b4bb620b4c
This commit is contained in:
parent
593a45e319
commit
e8e7a2db57
@ -11,7 +11,6 @@
|
|||||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*
|
*
|
||||||
* @provides ListViewPagingExample
|
|
||||||
* @flow
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
@ -27,11 +26,6 @@ var {
|
|||||||
View,
|
View,
|
||||||
} = React;
|
} = React;
|
||||||
|
|
||||||
var NativeModules = require('NativeModules');
|
|
||||||
var {
|
|
||||||
UIManager,
|
|
||||||
} = NativeModules;
|
|
||||||
|
|
||||||
var PAGE_SIZE = 4;
|
var PAGE_SIZE = 4;
|
||||||
var THUMB_URLS = [
|
var THUMB_URLS = [
|
||||||
'Thumbnails/like.png',
|
'Thumbnails/like.png',
|
||||||
@ -54,10 +48,6 @@ var Thumb = React.createClass({
|
|||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {thumbIndex: this._getThumbIdx(), dir: 'row'};
|
return {thumbIndex: this._getThumbIdx(), dir: 'row'};
|
||||||
},
|
},
|
||||||
componentWillMount: function() {
|
|
||||||
UIManager.setLayoutAnimationEnabledExperimental &&
|
|
||||||
UIManager.setLayoutAnimationEnabledExperimental(true);
|
|
||||||
},
|
|
||||||
_getThumbIdx: function() {
|
_getThumbIdx: function() {
|
||||||
return Math.floor(Math.random() * THUMB_URLS.length);
|
return Math.floor(Math.random() * THUMB_URLS.length);
|
||||||
},
|
},
|
||||||
|
@ -29,11 +29,9 @@ import com.facebook.react.bridge.Callback;
|
|||||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
|
||||||
import com.facebook.react.bridge.SoftAssertions;
|
import com.facebook.react.bridge.SoftAssertions;
|
||||||
import com.facebook.react.bridge.UiThreadUtil;
|
import com.facebook.react.bridge.UiThreadUtil;
|
||||||
import com.facebook.react.touch.JSResponderHandler;
|
import com.facebook.react.touch.JSResponderHandler;
|
||||||
import com.facebook.react.uimanager.layoutanimation.LayoutAnimationController;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate of {@link UIManagerModule} that owns the native view hierarchy and mapping between
|
* Delegate of {@link UIManagerModule} that owns the native view hierarchy and mapping between
|
||||||
@ -68,9 +66,6 @@ import com.facebook.react.uimanager.layoutanimation.LayoutAnimationController;
|
|||||||
private final ViewManagerRegistry mViewManagers;
|
private final ViewManagerRegistry mViewManagers;
|
||||||
private final JSResponderHandler mJSResponderHandler = new JSResponderHandler();
|
private final JSResponderHandler mJSResponderHandler = new JSResponderHandler();
|
||||||
private final RootViewManager mRootViewManager = new RootViewManager();
|
private final RootViewManager mRootViewManager = new RootViewManager();
|
||||||
private final LayoutAnimationController mLayoutAnimator = new LayoutAnimationController();
|
|
||||||
|
|
||||||
private boolean mLayoutAnimationEnabled;
|
|
||||||
|
|
||||||
public NativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
|
public NativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
|
||||||
mAnimationRegistry = new AnimationRegistry();
|
mAnimationRegistry = new AnimationRegistry();
|
||||||
@ -85,10 +80,6 @@ import com.facebook.react.uimanager.layoutanimation.LayoutAnimationController;
|
|||||||
return mAnimationRegistry;
|
return mAnimationRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLayoutAnimationEnabled(boolean enabled) {
|
|
||||||
mLayoutAnimationEnabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateProperties(int tag, CatalystStylesDiffMap props) {
|
public void updateProperties(int tag, CatalystStylesDiffMap props) {
|
||||||
UiThreadUtil.assertOnUiThread();
|
UiThreadUtil.assertOnUiThread();
|
||||||
|
|
||||||
@ -163,17 +154,8 @@ import com.facebook.react.uimanager.layoutanimation.LayoutAnimationController;
|
|||||||
}
|
}
|
||||||
if (parentViewGroupManager != null
|
if (parentViewGroupManager != null
|
||||||
&& !parentViewGroupManager.needsCustomLayoutForChildren()) {
|
&& !parentViewGroupManager.needsCustomLayoutForChildren()) {
|
||||||
updateLayout(viewToUpdate, x, y, width, height);
|
viewToUpdate.layout(x, y, x + width, y + height);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
updateLayout(viewToUpdate, x, y, width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateLayout(View viewToUpdate, int x, int y, int width, int height) {
|
|
||||||
if (mLayoutAnimationEnabled &&
|
|
||||||
mLayoutAnimator.shouldAnimateLayout(viewToUpdate)) {
|
|
||||||
mLayoutAnimator.applyLayoutUpdate(viewToUpdate, x, y, width, height);
|
|
||||||
} else {
|
} else {
|
||||||
viewToUpdate.layout(x, y, x + width, y + height);
|
viewToUpdate.layout(x, y, x + width, y + height);
|
||||||
}
|
}
|
||||||
@ -488,14 +470,6 @@ import com.facebook.react.uimanager.layoutanimation.LayoutAnimationController;
|
|||||||
mJSResponderHandler.clearJSResponder();
|
mJSResponderHandler.clearJSResponder();
|
||||||
}
|
}
|
||||||
|
|
||||||
void configureLayoutAnimation(final ReadableMap config) {
|
|
||||||
mLayoutAnimator.initializeFromConfig(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearLayoutAnimation() {
|
|
||||||
mLayoutAnimator.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ void startAnimationForNativeView(
|
/* package */ void startAnimationForNativeView(
|
||||||
int reactTag,
|
int reactTag,
|
||||||
Animation animation,
|
Animation animation,
|
||||||
|
@ -383,45 +383,12 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
|
|||||||
mUIImplementation.showPopupMenu(reactTag, items, error, success);
|
mUIImplementation.showPopupMenu(reactTag, items, error, success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
|
||||||
public void setMainScrollViewTag(int reactTag) {
|
|
||||||
// TODO(6588266): Implement if required
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled
|
|
||||||
* explicitly in order to avoid regression in existing application written for iOS using this API.
|
|
||||||
*
|
|
||||||
* Warning : This method will be removed in future version of React Native, and layout animation
|
|
||||||
* will be enabled by default, so always check for its existence before invoking it.
|
|
||||||
*
|
|
||||||
* TODO(9139831) : remove this method once layout animation is fully stable.
|
|
||||||
*
|
|
||||||
* @param enabled whether layout animation is enabled or not
|
|
||||||
*/
|
|
||||||
@ReactMethod
|
|
||||||
public void setLayoutAnimationEnabledExperimental(boolean enabled) {
|
|
||||||
mOperationsQueue.enqueueSetLayoutAnimationEnabled(enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure an animation to be used for the native layout changes, and native views
|
|
||||||
* creation. The animation will only apply during the current batch operations.
|
|
||||||
*
|
|
||||||
* TODO(7728153) : animating view deletion is currently not supported.
|
|
||||||
* TODO(7613721) : callbacks are not supported, this feature will likely be killed.
|
|
||||||
*
|
|
||||||
* @param config the configuration of the animation for view addition/removal/update.
|
|
||||||
* @param success will be called when the animation completes, or when the animation get
|
|
||||||
* interrupted. In this case, callback parameter will be false.
|
|
||||||
* @param error will be called if there was an error processing the animation
|
|
||||||
*/
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void configureNextLayoutAnimation(
|
public void configureNextLayoutAnimation(
|
||||||
ReadableMap config,
|
ReadableMap config,
|
||||||
Callback success,
|
Callback successCallback,
|
||||||
Callback error) {
|
Callback errorCallback) {
|
||||||
mOperationsQueue.enqueueConfigureLayoutAnimation(config, success, error);
|
// TODO(6588266): Implement if required
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,7 +23,6 @@ import com.facebook.react.bridge.ReactApplicationContext;
|
|||||||
import com.facebook.react.bridge.SoftAssertions;
|
import com.facebook.react.bridge.SoftAssertions;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
|
||||||
import com.facebook.react.bridge.UiThreadUtil;
|
import com.facebook.react.bridge.UiThreadUtil;
|
||||||
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
|
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
|
||||||
import com.facebook.systrace.Systrace;
|
import com.facebook.systrace.Systrace;
|
||||||
@ -323,32 +322,6 @@ public class UIViewOperationQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SetLayoutAnimationEnabledOperation implements UIOperation {
|
|
||||||
private final boolean mEnabled;
|
|
||||||
|
|
||||||
private SetLayoutAnimationEnabledOperation(final boolean enabled) {
|
|
||||||
mEnabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute() {
|
|
||||||
mNativeViewHierarchyManager.setLayoutAnimationEnabled(mEnabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ConfigureLayoutAnimationOperation implements UIOperation {
|
|
||||||
private final ReadableMap mConfig;
|
|
||||||
|
|
||||||
private ConfigureLayoutAnimationOperation(final ReadableMap config) {
|
|
||||||
mConfig = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute() {
|
|
||||||
mNativeViewHierarchyManager.configureLayoutAnimation(mConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class MeasureOperation implements UIOperation {
|
private final class MeasureOperation implements UIOperation {
|
||||||
|
|
||||||
private final int mReactTag;
|
private final int mReactTag;
|
||||||
@ -603,18 +576,6 @@ public class UIViewOperationQueue {
|
|||||||
mOperations.add(new RemoveAnimationOperation(animationID));
|
mOperations.add(new RemoveAnimationOperation(animationID));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enqueueSetLayoutAnimationEnabled(
|
|
||||||
final boolean enabled) {
|
|
||||||
mOperations.add(new SetLayoutAnimationEnabledOperation(enabled));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enqueueConfigureLayoutAnimation(
|
|
||||||
final ReadableMap config,
|
|
||||||
final Callback onSuccess,
|
|
||||||
final Callback onError) {
|
|
||||||
mOperations.add(new ConfigureLayoutAnimationOperation(config));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enqueueMeasure(
|
public void enqueueMeasure(
|
||||||
final int reactTag,
|
final int reactTag,
|
||||||
final Callback callback) {
|
final Callback callback) {
|
||||||
@ -711,9 +672,6 @@ public class UIViewOperationQueue {
|
|||||||
mDispatchUIRunnables.get(i).run();
|
mDispatchUIRunnables.get(i).run();
|
||||||
}
|
}
|
||||||
mDispatchUIRunnables.clear();
|
mDispatchUIRunnables.clear();
|
||||||
|
|
||||||
// Clear layout animation, as animation only apply to current UI operations batch.
|
|
||||||
mNativeViewHierarchyManager.clearLayoutAnimation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactChoreographer.getInstance().postFrameCallback(
|
ReactChoreographer.getInstance().postFrameCallback(
|
||||||
|
@ -1,108 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
|
||||||
import android.view.animation.AccelerateInterpolator;
|
|
||||||
import android.view.animation.Animation;
|
|
||||||
import android.view.animation.DecelerateInterpolator;
|
|
||||||
import android.view.animation.Interpolator;
|
|
||||||
import android.view.animation.LinearInterpolator;
|
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
|
||||||
import com.facebook.react.common.MapBuilder;
|
|
||||||
import com.facebook.react.uimanager.IllegalViewOperationException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class responsible for parsing and converting layout animation data into native {@link Animation}
|
|
||||||
* in order to animate layout when a valid configuration has been supplied by the application.
|
|
||||||
*/
|
|
||||||
/* package */ abstract class AbstractLayoutAnimation {
|
|
||||||
|
|
||||||
// Forces animation to be playing 10x slower, used for debug purposes.
|
|
||||||
private static final boolean SLOWDOWN_ANIMATION_MODE = false;
|
|
||||||
|
|
||||||
abstract boolean isValid();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an animation object for the current animation type, based on the view and final screen
|
|
||||||
* coordinates. If the application-supplied configuraiton does not specify an animation definition
|
|
||||||
* for this types, or if the animation definition is invalid, returns null.
|
|
||||||
*/
|
|
||||||
abstract @Nullable Animation createAnimationImpl(View view, int x, int y, int width, int height);
|
|
||||||
|
|
||||||
private static final Map<InterpolatorType, Interpolator> INTERPOLATOR = MapBuilder.of(
|
|
||||||
InterpolatorType.LINEAR, new LinearInterpolator(),
|
|
||||||
InterpolatorType.EASE_IN, new AccelerateInterpolator(),
|
|
||||||
InterpolatorType.EASE_OUT, new DecelerateInterpolator(),
|
|
||||||
InterpolatorType.EASE_IN_EASE_OUT, new AccelerateDecelerateInterpolator(),
|
|
||||||
InterpolatorType.SPRING, new SimpleSpringInterpolator());
|
|
||||||
|
|
||||||
private @Nullable Interpolator mInterpolator;
|
|
||||||
private int mDelayMs;
|
|
||||||
|
|
||||||
protected @Nullable AnimatedPropertyType mAnimatedProperty;
|
|
||||||
protected int mDurationMs;
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
mAnimatedProperty = null;
|
|
||||||
mDurationMs = 0;
|
|
||||||
mDelayMs = 0;
|
|
||||||
mInterpolator = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initializeFromConfig(ReadableMap data, int globalDuration) {
|
|
||||||
mAnimatedProperty = data.hasKey("property") ?
|
|
||||||
AnimatedPropertyType.fromString(data.getString("property")) : null;
|
|
||||||
mDurationMs = data.hasKey("duration") ? data.getInt("duration") : globalDuration;
|
|
||||||
mDelayMs = data.hasKey("delay") ? data.getInt("delay") : 0;
|
|
||||||
mInterpolator = data.hasKey("type") ?
|
|
||||||
getInterpolator(InterpolatorType.fromString(data.getString("type"))) : null;
|
|
||||||
|
|
||||||
if (!isValid()) {
|
|
||||||
throw new IllegalViewOperationException("Invalid layout animation : " + data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an animation object to be used to animate the view, based on the animation config
|
|
||||||
* supplied at initialization time and the new view position and size.
|
|
||||||
*
|
|
||||||
* @param view the view to create the animation for
|
|
||||||
* @param x the new X position for the view
|
|
||||||
* @param y the new Y position for the view
|
|
||||||
* @param width the new width value for the view
|
|
||||||
* @param height the new height value for the view
|
|
||||||
*/
|
|
||||||
public final @Nullable Animation createAnimation(
|
|
||||||
View view,
|
|
||||||
int x,
|
|
||||||
int y,
|
|
||||||
int width,
|
|
||||||
int height) {
|
|
||||||
if (!isValid()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Animation animation = createAnimationImpl(view, x, y, width, height);
|
|
||||||
if (animation != null) {
|
|
||||||
int slowdownFactor = SLOWDOWN_ANIMATION_MODE ? 10 : 1;
|
|
||||||
animation.setDuration(mDurationMs * slowdownFactor);
|
|
||||||
animation.setStartOffset(mDelayMs * slowdownFactor);
|
|
||||||
animation.setInterpolator(mInterpolator);
|
|
||||||
}
|
|
||||||
return animation;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Interpolator getInterpolator(InterpolatorType type) {
|
|
||||||
Interpolator interpolator = INTERPOLATOR.get(type);
|
|
||||||
if (interpolator == null) {
|
|
||||||
throw new IllegalArgumentException("Missing interpolator for type : " + type);
|
|
||||||
}
|
|
||||||
return interpolator;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum representing the different view properties that can be used when animating layout for
|
|
||||||
* view creation.
|
|
||||||
*/
|
|
||||||
/* package */ enum AnimatedPropertyType {
|
|
||||||
OPACITY("opacity"),
|
|
||||||
SCALE_XY("scaleXY");
|
|
||||||
|
|
||||||
private final String mName;
|
|
||||||
|
|
||||||
private AnimatedPropertyType(String name) {
|
|
||||||
mName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AnimatedPropertyType fromString(String name) {
|
|
||||||
for (AnimatedPropertyType property : AnimatedPropertyType.values()) {
|
|
||||||
if (property.toString().equalsIgnoreCase(name)) {
|
|
||||||
return property;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Unsupported animated property : " + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.animation.Animation;
|
|
||||||
import android.view.animation.ScaleAnimation;
|
|
||||||
|
|
||||||
import com.facebook.react.uimanager.IllegalViewOperationException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class responsible for default layout animation, i.e animation of view creation and deletion.
|
|
||||||
*/
|
|
||||||
/* package */ abstract class BaseLayoutAnimation extends AbstractLayoutAnimation {
|
|
||||||
|
|
||||||
abstract boolean isReverse();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean isValid() {
|
|
||||||
return mDurationMs > 0 && mAnimatedProperty != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Animation createAnimationImpl(View view, int x, int y, int width, int height) {
|
|
||||||
float fromValue = isReverse() ? 1.0f : 0.0f;
|
|
||||||
float toValue = isReverse() ? 0.0f : 1.0f;
|
|
||||||
if (mAnimatedProperty != null) {
|
|
||||||
switch (mAnimatedProperty) {
|
|
||||||
case OPACITY:
|
|
||||||
return new OpacityAnimation(view, fromValue, toValue);
|
|
||||||
case SCALE_XY:
|
|
||||||
return new ScaleAnimation(
|
|
||||||
fromValue,
|
|
||||||
toValue,
|
|
||||||
fromValue,
|
|
||||||
toValue,
|
|
||||||
Animation.RELATIVE_TO_PARENT,
|
|
||||||
.5f,
|
|
||||||
Animation.RELATIVE_TO_PARENT,
|
|
||||||
.5f);
|
|
||||||
default:
|
|
||||||
throw new IllegalViewOperationException(
|
|
||||||
"Missing animation for property : " + mAnimatedProperty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalViewOperationException("Missing animated property from animation config");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marker interface to indicate a given animation type takes care of updating the view layout.
|
|
||||||
*/
|
|
||||||
/* package */ interface HandleLayout {
|
|
||||||
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum representing the different interpolators that can be used in layout animation configuration.
|
|
||||||
*/
|
|
||||||
/* package */ enum InterpolatorType {
|
|
||||||
LINEAR("linear"),
|
|
||||||
EASE_IN("easeIn"),
|
|
||||||
EASE_OUT("easeOut"),
|
|
||||||
EASE_IN_EASE_OUT("easeInEaseOut"),
|
|
||||||
SPRING("spring");
|
|
||||||
|
|
||||||
private final String mName;
|
|
||||||
|
|
||||||
private InterpolatorType(String name) {
|
|
||||||
mName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InterpolatorType fromString(String name) {
|
|
||||||
for (InterpolatorType type : InterpolatorType.values()) {
|
|
||||||
if (type.toString().equalsIgnoreCase(name)) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Unsupported interpolation type : " + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.animation.Animation;
|
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
|
||||||
import com.facebook.react.bridge.UiThreadUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class responsible for animation layout changes, if a valid layout animation config has been
|
|
||||||
* supplied. If not animation is available, layout change is applied immediately instead of
|
|
||||||
* performing an animation.
|
|
||||||
*
|
|
||||||
* TODO(7613721): Invoke success callback at the end of animation and when animation gets cancelled.
|
|
||||||
*/
|
|
||||||
@NotThreadSafe
|
|
||||||
public class LayoutAnimationController {
|
|
||||||
|
|
||||||
private static final boolean ENABLED = true;
|
|
||||||
|
|
||||||
private final AbstractLayoutAnimation mLayoutCreateAnimation = new LayoutCreateAnimation();
|
|
||||||
private final AbstractLayoutAnimation mLayoutUpdateAnimation = new LayoutUpdateAnimation();
|
|
||||||
private boolean mShouldAnimateLayout;
|
|
||||||
|
|
||||||
public void initializeFromConfig(final @Nullable ReadableMap config) {
|
|
||||||
if (!ENABLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config == null) {
|
|
||||||
reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mShouldAnimateLayout = false;
|
|
||||||
int globalDuration = config.hasKey("duration") ? config.getInt("duration") : 0;
|
|
||||||
if (config.hasKey(LayoutAnimationType.CREATE.toString())) {
|
|
||||||
mLayoutCreateAnimation.initializeFromConfig(
|
|
||||||
config.getMap(LayoutAnimationType.CREATE.toString()), globalDuration);
|
|
||||||
mShouldAnimateLayout = true;
|
|
||||||
}
|
|
||||||
if (config.hasKey(LayoutAnimationType.UPDATE.toString())) {
|
|
||||||
mLayoutUpdateAnimation.initializeFromConfig(
|
|
||||||
config.getMap(LayoutAnimationType.UPDATE.toString()), globalDuration);
|
|
||||||
mShouldAnimateLayout = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
mLayoutCreateAnimation.reset();
|
|
||||||
mLayoutUpdateAnimation.reset();
|
|
||||||
mShouldAnimateLayout = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldAnimateLayout(View viewToAnimate) {
|
|
||||||
// if view parent is null, skip animation: view have been clipped, we don't want animation to
|
|
||||||
// resume when view is re-attached to parent, which is the standard android animation behavior.
|
|
||||||
return mShouldAnimateLayout && viewToAnimate.getParent() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update layout of given view, via immediate update or animation depending on the current batch
|
|
||||||
* layout animation configuration supplied during initialization.
|
|
||||||
*
|
|
||||||
* @param view the view to update layout of
|
|
||||||
* @param x the new X position for the view
|
|
||||||
* @param y the new Y position for the view
|
|
||||||
* @param width the new width value for the view
|
|
||||||
* @param height the new height value for the view
|
|
||||||
*/
|
|
||||||
public void applyLayoutUpdate(View view, int x, int y, int width, int height) {
|
|
||||||
UiThreadUtil.assertOnUiThread();
|
|
||||||
|
|
||||||
// Determine which animation to use : if view is initially invisible, use create animation.
|
|
||||||
// If view is becoming invisible, use delete animation. Otherwise, use update animation.
|
|
||||||
// This approach is easier than maintaining a list of tags for recently created/deleted views.
|
|
||||||
AbstractLayoutAnimation layoutAnimation = (view.getWidth() == 0 || view.getHeight() == 0) ?
|
|
||||||
mLayoutCreateAnimation :
|
|
||||||
mLayoutUpdateAnimation;
|
|
||||||
|
|
||||||
Animation animation = layoutAnimation.createAnimation(view, x, y, width, height);
|
|
||||||
if (animation == null || !(animation instanceof HandleLayout)) {
|
|
||||||
view.layout(x, y, x + width, y + height);
|
|
||||||
}
|
|
||||||
if (animation != null) {
|
|
||||||
view.startAnimation(animation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum representing the different animation type that can be specified in layout animation config.
|
|
||||||
*/
|
|
||||||
/* package */ enum LayoutAnimationType {
|
|
||||||
CREATE("create"),
|
|
||||||
UPDATE("update");
|
|
||||||
|
|
||||||
private final String mName;
|
|
||||||
|
|
||||||
private LayoutAnimationType(String name) {
|
|
||||||
mName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class responsible for handling layout view creation animation, applied to view whenever a
|
|
||||||
* valid config was supplied for the layout animation of CREATE type.
|
|
||||||
*/
|
|
||||||
/* package */ class LayoutCreateAnimation extends BaseLayoutAnimation {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean isReverse() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.animation.Animation;
|
|
||||||
import android.view.animation.TranslateAnimation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class responsible for handling layout update animation, applied to view whenever a valid config
|
|
||||||
* was supplied for the layout animation of UPDATE type.
|
|
||||||
*/
|
|
||||||
/* package */ class LayoutUpdateAnimation extends AbstractLayoutAnimation {
|
|
||||||
|
|
||||||
// We are currently not enabling translation GPU-accelerated animated, as it creates odd
|
|
||||||
// artifacts with native react scrollview. This needs to be investigated.
|
|
||||||
private static final boolean USE_TRANSLATE_ANIMATION = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean isValid() {
|
|
||||||
return mDurationMs > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable Animation createAnimationImpl(View view, int x, int y, int width, int height) {
|
|
||||||
boolean animateLocation = view.getX() != x || view.getY() != y;
|
|
||||||
boolean animateSize = view.getWidth() != width || view.getHeight() != height;
|
|
||||||
if (!animateLocation && !animateSize) {
|
|
||||||
return null;
|
|
||||||
} else if (animateLocation && !animateSize && USE_TRANSLATE_ANIMATION) {
|
|
||||||
// Use GPU-accelerated animation, however we loose the ability to resume interrupted
|
|
||||||
// animation where it was left off. We may be able to listen to animation interruption
|
|
||||||
// and set the layout manually in this case, so that next animation kicks off smoothly.
|
|
||||||
return new TranslateAnimation(view.getX() - x, 0, view.getY() - y, 0);
|
|
||||||
} else {
|
|
||||||
// Animation is sub-optimal for perf, but scale transformation can't be use in this case.
|
|
||||||
return new PositionAndSizeAnimation(view, x, y, width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.animation.Animation;
|
|
||||||
import android.view.animation.Transformation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Animation responsible for updating opacity of a view. It should ideally use hardware texture
|
|
||||||
* to optimize rendering performances.
|
|
||||||
*/
|
|
||||||
/* package */ class OpacityAnimation extends Animation {
|
|
||||||
|
|
||||||
static class OpacityAnimationListener implements AnimationListener {
|
|
||||||
|
|
||||||
private final View mView;
|
|
||||||
private boolean mLayerTypeChanged = false;
|
|
||||||
|
|
||||||
public OpacityAnimationListener(View view) {
|
|
||||||
mView = view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationStart(Animation animation) {
|
|
||||||
if (mView.hasOverlappingRendering() &&
|
|
||||||
mView.getLayerType() == View.LAYER_TYPE_NONE) {
|
|
||||||
mLayerTypeChanged = true;
|
|
||||||
mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animation animation) {
|
|
||||||
if (mLayerTypeChanged) {
|
|
||||||
mView.setLayerType(View.LAYER_TYPE_NONE, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationRepeat(Animation animation) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final View mView;
|
|
||||||
private final float mStartOpacity, mDeltaOpacity;
|
|
||||||
|
|
||||||
public OpacityAnimation(View view, float startOpacity, float endOpacity) {
|
|
||||||
mView = view;
|
|
||||||
mStartOpacity = startOpacity;
|
|
||||||
mDeltaOpacity = endOpacity - startOpacity;
|
|
||||||
|
|
||||||
setAnimationListener(new OpacityAnimationListener(view));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
|
||||||
mView.setAlpha(mStartOpacity + mDeltaOpacity * interpolatedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean willChangeBounds() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.animation.Animation;
|
|
||||||
import android.view.animation.Transformation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Animation responsible for updating size and position of a view. We can't use scaling as view
|
|
||||||
* content may not necessarily stretch. As a result, this approach is inefficient because of
|
|
||||||
* layout passes occurring on every frame.
|
|
||||||
* What we might want to try to do instead is use a combined ScaleAnimation and TranslateAnimation.
|
|
||||||
*/
|
|
||||||
/* package */ class PositionAndSizeAnimation extends Animation implements HandleLayout {
|
|
||||||
|
|
||||||
private final View mView;
|
|
||||||
private final float mStartX, mStartY, mDeltaX, mDeltaY;
|
|
||||||
private final int mStartWidth, mStartHeight, mDeltaWidth, mDeltaHeight;
|
|
||||||
|
|
||||||
public PositionAndSizeAnimation(View view, int x, int y, int width, int height) {
|
|
||||||
mView = view;
|
|
||||||
|
|
||||||
mStartX = view.getX();
|
|
||||||
mStartY = view.getY();
|
|
||||||
mStartWidth = view.getWidth();
|
|
||||||
mStartHeight = view.getHeight();
|
|
||||||
|
|
||||||
mDeltaX = x - mStartX;
|
|
||||||
mDeltaY = y - mStartY;
|
|
||||||
mDeltaWidth = width - mStartWidth;
|
|
||||||
mDeltaHeight = height - mStartHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
|
||||||
float newX = mStartX + mDeltaX * interpolatedTime;
|
|
||||||
float newY = mStartY + mDeltaY * interpolatedTime;
|
|
||||||
float newWidth = mStartWidth + mDeltaWidth * interpolatedTime;
|
|
||||||
float newHeight = mStartHeight + mDeltaHeight * interpolatedTime;
|
|
||||||
mView.layout(
|
|
||||||
Math.round(newX),
|
|
||||||
Math.round(newY),
|
|
||||||
Math.round(newX + newWidth),
|
|
||||||
Math.round(newY + newHeight));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean willChangeBounds() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
||||||
|
|
||||||
package com.facebook.react.uimanager.layoutanimation;
|
|
||||||
|
|
||||||
import android.view.animation.Interpolator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple spring interpolator
|
|
||||||
*/
|
|
||||||
//TODO(7613736): Improve spring interpolator with friction and damping variable support
|
|
||||||
/* package */ class SimpleSpringInterpolator implements Interpolator {
|
|
||||||
|
|
||||||
private static final float FACTOR = 0.5f;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getInterpolation(float input) {
|
|
||||||
return (float)
|
|
||||||
(1 + Math.pow(2, -10 * input) * Math.sin((input - FACTOR / 4) * Math.PI * 2 / FACTOR));
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,7 +16,6 @@ import android.graphics.Color;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.LayerDrawable;
|
import android.graphics.drawable.LayerDrawable;
|
||||||
import android.view.animation.Animation;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -287,15 +286,7 @@ public class ReactViewGroup extends ViewGroup implements
|
|||||||
boolean intersects = clippingRect
|
boolean intersects = clippingRect
|
||||||
.intersects(sHelperRect.left, sHelperRect.top, sHelperRect.right, sHelperRect.bottom);
|
.intersects(sHelperRect.left, sHelperRect.top, sHelperRect.right, sHelperRect.bottom);
|
||||||
boolean needUpdateClippingRecursive = false;
|
boolean needUpdateClippingRecursive = false;
|
||||||
// We never want to clip children that are being animated, as this can easily break layout :
|
if (!intersects && child.getParent() != null) {
|
||||||
// when layout animation changes size and/or position of views contained inside a listview that
|
|
||||||
// clips offscreen children, we need to ensure that, when view exits the viewport, final size
|
|
||||||
// and position is set prior to removing the view from its listview parent.
|
|
||||||
// Otherwise, when view gets re-attached again, i.e when it re-enters the viewport after scroll,
|
|
||||||
// it won't be size and located properly.
|
|
||||||
Animation animation = child.getAnimation();
|
|
||||||
boolean isAnimating = animation != null && !animation.hasEnded();
|
|
||||||
if (!intersects && child.getParent() != null && !isAnimating) {
|
|
||||||
// We can try saving on invalidate call here as the view that we remove is out of visible area
|
// We can try saving on invalidate call here as the view that we remove is out of visible area
|
||||||
// therefore invalidation is not necessary.
|
// therefore invalidation is not necessary.
|
||||||
super.removeViewsInLayout(idx - clippedSoFar, 1);
|
super.removeViewsInLayout(idx - clippedSoFar, 1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user