Files
react-native/ReactAndroid/src/main/java/com/facebook/react/flat/FlatNativeViewHierarchyManager.java
Ahmed El-Helw 9d67989001 Don't clip overflowing Nodes
Summary:
As of D3235050, Nodes supports the optimization of removing clipped
subviews from the hierarchy. However, because Nodes supports overflow:visible,
this could cause issues when DrawCommands overflow the bounds of their parent
container. This patch fixes this by not clipping any overflowing Nodes.

Reviewed By: astreet

Differential Revision: D3235072
2016-12-19 13:40:26 -08:00

153 lines
5.3 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,
boolean hasOverflowingElements) {
FlatViewGroup view = (FlatViewGroup) resolveView(reactTag);
if (drawCommands != null) {
view.mountDrawCommands(drawCommands, hasOverflowingElements);
}
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);
}
}
}
}