Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,9 @@ public synchronized void manageChildren(
if (mLayoutAnimationEnabled &&
mLayoutAnimator.shouldAnimateLayout(viewToRemove) &&
arrayContains(tagsToDelete, viewToRemove.getId())) {
// The view will be removed and dropped by the 'delete' layout animation
// instead, so do nothing
// Only remove the view from the 'React' view hierarchy, it will be removed from native
// at the end of the layout delete animation.
viewManager.removeReactViewAt(viewToManage, indexToRemove);
} else {
viewManager.removeViewAt(viewToManage, indexToRemove);
}
Expand Down Expand Up @@ -423,7 +424,7 @@ public synchronized void manageChildren(
mLayoutAnimator.deleteView(viewToDestroy, new LayoutAnimationListener() {
@Override
public void onAnimationEnd() {
viewManager.removeView(viewToManage, viewToDestroy);
viewManager.removeNativeView(viewToManage, viewToDestroy);
dropView(viewToDestroy);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
package com.facebook.react.uimanager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.WeakHashMap;

Expand All @@ -28,6 +25,9 @@ public abstract class ViewGroupManager <T extends ViewGroup>
extends BaseViewManager<T, LayoutShadowNode> {

private static WeakHashMap<View, Integer> mZIndexHash = new WeakHashMap<>();
// This is used to remove views from the React view hierarchy but keep them in the Native one.
// Mapping from the parent view to a list of its children.
private static WeakHashMap<View, List<View>> mReactChildrenMap = new WeakHashMap<>();

@Override
public LayoutShadowNode createShadowNodeInstance() {
Expand All @@ -44,7 +44,19 @@ public void updateExtraData(T root, Object extraData) {
}

public void addView(T parent, View child, int index) {
parent.addView(child, index);
List<View> reactChildren = mReactChildrenMap.get(parent);
if (reactChildren != null) {
reactChildren.add(index, child);
if (index == reactChildren.size() - 1) {
parent.addView(child);
} else {
View addBeforeView = reactChildren.get(index + 1);
int addBeforeIndex = parent.indexOfChild(addBeforeView);
parent.addView(child, addBeforeIndex - 1);
}
} else {
parent.addView(child, index);
}
}

/**
Expand All @@ -69,15 +81,36 @@ public static void setViewZIndex(View view, int zIndex) {
}

public int getChildCount(T parent) {
return parent.getChildCount();
List<View> reactChildren = mReactChildrenMap.get(parent);
if (reactChildren != null) {
return reactChildren.size();
} else {
return parent.getChildCount();
}
}

public View getChildAt(T parent, int index) {
return parent.getChildAt(index);
List<View> reactChildren = mReactChildrenMap.get(parent);
if (reactChildren != null) {
return reactChildren.get(index);
} else {
return parent.getChildAt(index);
}
}

public void removeViewAt(T parent, int index) {
parent.removeViewAt(index);
List<View> reactChildren = mReactChildrenMap.get(parent);
if (reactChildren != null) {
View removedView = reactChildren.remove(index);
if (removedView != null) {
parent.removeView(removedView);
}
mReactChildrenMap.remove(removedView);
} else {
View removedView = parent.getChildAt(index);
parent.removeViewAt(index);
mReactChildrenMap.remove(removedView);
}
}

public void removeView(T parent, View view) {
Expand All @@ -95,6 +128,35 @@ public void removeAllViews(T parent) {
}
}

/**
* Remove a view from the React view hierarchy but keep the actual native view there. Use
* {@link ViewGroupManager#removeNativeView} to remove it completely.
*/
public void removeReactViewAt(T parent, int index) {
List<View> reactChildren = mReactChildrenMap.get(parent);

// Create the React children mapping lazily the first time it diverges from native.
if (reactChildren == null) {
reactChildren = new ArrayList<>(parent.getChildCount());
for (int i = 0; i < parent.getChildCount(); i++) {
reactChildren.add(parent.getChildAt(i));
}
mReactChildrenMap.put(parent, reactChildren);
}
reactChildren.remove(index);
}

/**
* Remove a view that was previously removed from the React view hierarchy but not from native.
*/
public void removeNativeView(T parent, View view) {
List<View> reactChildren = mReactChildrenMap.get(parent);
if (reactChildren != null) {
reactChildren.remove(view);
}
parent.removeView(view);
}

/**
* Returns whether this View type needs to handle laying out its own children instead of
* deferring to the standard css-layout algorithm.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public void applyLayoutUpdate(View view, int x, int y, int width, int height) {
view.layout(x, y, x + width, y + height);
}
if (animation != null) {
view.clearAnimation();
view.startAnimation(animation);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
static class OpacityAnimationListener implements AnimationListener {

private final View mView;
private final float mEndOpacity;
private boolean mLayerTypeChanged = false;

public OpacityAnimationListener(View view) {
public OpacityAnimationListener(View view, float endOpacity) {
mView = view;
mEndOpacity = endOpacity;
}

@Override
Expand All @@ -35,6 +37,7 @@ public void onAnimationEnd(Animation animation) {
if (mLayerTypeChanged) {
mView.setLayerType(View.LAYER_TYPE_NONE, null);
}
mView.setAlpha(mEndOpacity);
}

@Override
Expand All @@ -51,7 +54,7 @@ public OpacityAnimation(View view, float startOpacity, float endOpacity) {
mStartOpacity = startOpacity;
mDeltaOpacity = endOpacity - startOpacity;

setAnimationListener(new OpacityAnimationListener(view));
setAnimationListener(new OpacityAnimationListener(view, endOpacity));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ public void addView(ReactViewGroup parent, View child, int index) {
if (removeClippedSubviews) {
parent.addViewWithSubviewClippingEnabled(child, index);
} else {
parent.addView(child, index);
super.addView(parent, child, index);
}
}

Expand All @@ -216,7 +216,7 @@ public int getChildCount(ReactViewGroup parent) {
if (removeClippedSubviews) {
return parent.getAllChildrenCount();
} else {
return parent.getChildCount();
return super.getChildCount(parent);
}
}

Expand All @@ -226,7 +226,7 @@ public View getChildAt(ReactViewGroup parent, int index) {
if (removeClippedSubviews) {
return parent.getChildAtWithSubviewClippingEnabled(index);
} else {
return parent.getChildAt(index);
return super.getChildAt(parent, index);
}
}

Expand All @@ -240,7 +240,7 @@ public void removeViewAt(ReactViewGroup parent, int index) {
}
parent.removeViewWithSubviewClippingEnabled(child);
} else {
parent.removeViewAt(index);
super.removeViewAt(parent, index);
}
}

Expand All @@ -250,7 +250,7 @@ public void removeAllViews(ReactViewGroup parent) {
if (removeClippedSubviews) {
parent.removeAllViewsWithSubviewClippingEnabled();
} else {
parent.removeAllViews();
super.removeAllViews(parent);
}
}
}