mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
461871364b
Summary: Nodes create a FlatViewGroup for a root node element, and NativeViewHierarchyManager assigns it an id that matches root node it. Now this top-level FlatViewGroup is added to a ReactRootView. In non-nodes, this ReactRootView has an id that matches root View id, and when this ReactRootView gets detached from Window, it sends an event to NativeViewHierarchyManager that says that all the children of this View must be removed recursively. This works great in non-Nodes, but fails in Nodes because ReactRootView has no id (-1) and NativeViewHierarchyManager fails to find a corresponding ReactShadowNode, throwing an Exception. To fix the issue and make it work again we need to assign this View id of the top level shadow node. This creates a minor issue, where 2 Views (ReactRootView and its only child) share the same id, but that is not a problem because we don't enforce uniqueness of the ids, and don't rely on getViewById(). This was originally implemented, but then I removed it because I thought it wasn't truly needed. Turns out, it is needed. Reviewed By: sriramramani Differential Revision: D2873995
152 lines
5.2 KiB
Java
152 lines
5.2 KiB
Java
/**
|
|
* 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.flat;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import android.view.View;
|
|
import android.view.View.MeasureSpec;
|
|
import android.view.ViewGroup;
|
|
|
|
import com.facebook.react.uimanager.NativeViewHierarchyManager;
|
|
import com.facebook.react.uimanager.SizeMonitoringFrameLayout;
|
|
import com.facebook.react.uimanager.ThemedReactContext;
|
|
import com.facebook.react.uimanager.ViewGroupManager;
|
|
import com.facebook.react.uimanager.ViewManagerRegistry;
|
|
|
|
/**
|
|
* FlatNativeViewHierarchyManager is the only class that performs View manipulations. All of this
|
|
* class methods can only be called from UI thread by {@link FlatUIViewOperationQueue}.
|
|
*/
|
|
/* package */ final class FlatNativeViewHierarchyManager extends NativeViewHierarchyManager
|
|
implements ViewResolver {
|
|
|
|
/* package */ FlatNativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
|
|
super(viewManagers);
|
|
}
|
|
|
|
@Override
|
|
public View getView(int reactTag) {
|
|
return super.resolveView(reactTag);
|
|
}
|
|
|
|
@Override
|
|
public void addRootView(
|
|
int tag,
|
|
SizeMonitoringFrameLayout view,
|
|
ThemedReactContext themedContext) {
|
|
FlatViewGroup root = new FlatViewGroup(themedContext);
|
|
view.addView(root);
|
|
|
|
// When unmounting, ReactInstanceManager.detachViewFromInstance() will check id of the
|
|
// top-level View (SizeMonitoringFrameLayout) and pass it back to JS. We want that View's id to
|
|
// be set, otherwise NativeViewHierarchyManager will not be able to cleanup properly.
|
|
view.setId(tag);
|
|
|
|
addRootViewGroup(tag, root, themedContext);
|
|
}
|
|
|
|
/**
|
|
* Updates DrawCommands and AttachDetachListeners of a FlatViewGroup specified by a reactTag.
|
|
*
|
|
* @param reactTag reactTag to lookup FlatViewGroup by
|
|
* @param drawCommands if non-null, new draw commands to execute during the drawing.
|
|
* @param listeners if non-null, new attach-detach listeners.
|
|
*/
|
|
/* package */ void updateMountState(
|
|
int reactTag,
|
|
@Nullable DrawCommand[] drawCommands,
|
|
@Nullable AttachDetachListener[] listeners,
|
|
@Nullable NodeRegion[] nodeRegions) {
|
|
FlatViewGroup view = (FlatViewGroup) resolveView(reactTag);
|
|
if (drawCommands != null) {
|
|
view.mountDrawCommands(drawCommands);
|
|
}
|
|
if (listeners != null) {
|
|
view.mountAttachDetachListeners(listeners);
|
|
}
|
|
if (nodeRegions != null) {
|
|
view.mountNodeRegions(nodeRegions);
|
|
}
|
|
}
|
|
|
|
/* package */ void updateViewGroup(int reactTag, int[] viewsToAdd, int[] viewsToDetach) {
|
|
View view = resolveView(reactTag);
|
|
if (view instanceof FlatViewGroup) {
|
|
((FlatViewGroup) view).mountViews(this, viewsToAdd, viewsToDetach);
|
|
return;
|
|
}
|
|
|
|
ViewGroup viewGroup = (ViewGroup) view;
|
|
ViewGroupManager viewManager = (ViewGroupManager) resolveViewManager(reactTag);
|
|
for (int i = 0; i < viewsToAdd.length; ++i) {
|
|
int tag = Math.abs(viewsToAdd[i]);
|
|
viewManager.addView(viewGroup, resolveView(tag), i);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates View bounds, possibly re-measuring and re-layouting it if the size changed.
|
|
*
|
|
* @param reactTag reactTag to lookup a View by
|
|
* @param left left coordinate relative to parent
|
|
* @param top top coordinate relative to parent
|
|
* @param right right coordinate relative to parent
|
|
* @param bottom bottom coordinate relative to parent
|
|
*/
|
|
/* package */ void updateViewBounds(int reactTag, int left, int top, int right, int bottom) {
|
|
View view = resolveView(reactTag);
|
|
int width = right - left;
|
|
int height = bottom - top;
|
|
if (view.getWidth() != width || view.getHeight() != height) {
|
|
// size changed, we need to measure and layout the View
|
|
view.measure(
|
|
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
|
|
view.layout(left, top, right, bottom);
|
|
} else {
|
|
// same size, only location changed, there is a faster route.
|
|
view.offsetLeftAndRight(left - view.getLeft());
|
|
view.offsetTopAndBottom(top - view.getTop());
|
|
}
|
|
}
|
|
|
|
/* package */ void setPadding(
|
|
int reactTag,
|
|
int paddingLeft,
|
|
int paddingTop,
|
|
int paddingRight,
|
|
int paddingBottom) {
|
|
resolveView(reactTag).setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
|
|
}
|
|
|
|
/* package */ void dropViews(int[] viewsToDrop) {
|
|
for (int viewToDrop : viewsToDrop) {
|
|
dropView(resolveView(viewToDrop));
|
|
}
|
|
}
|
|
|
|
/* package */ void detachAllChildrenFromViews(int[] viewsToDetachAllChildrenFrom) {
|
|
for (int viewTag : viewsToDetachAllChildrenFrom) {
|
|
View view = resolveView(viewTag);
|
|
if (view instanceof FlatViewGroup) {
|
|
((FlatViewGroup) view).detachAllViewsFromParent();
|
|
continue;
|
|
}
|
|
|
|
ViewGroup viewGroup = (ViewGroup) view;
|
|
ViewGroupManager viewManager = (ViewGroupManager) resolveViewManager(viewTag);
|
|
for (int i = viewManager.getChildCount(viewGroup) - 1; i >= 0; --i) {
|
|
viewManager.removeViewAt(viewGroup, i);
|
|
}
|
|
}
|
|
}
|
|
}
|