Properly clip child Views in FlatViewGroup
Summary: Everything (but Views) are drawn using AbstractDrawCommand (or its derivative, like DrawBorder or DrawBackgroundColor) and supports clipping properly. Views however are drawn using an assumption that Android will clip them manually. This is however not always true. One example is if an element A mounts to a View, and its parent B doesn't but has overflow: hidden and thus should clip the child. There are 2 ways to fix this: - pop every element that has overflow: hidden to its own View. In this case, its children will always be correctly clipped. This is however very inefficient, especially if overflow: hidden is default (which it is!) which means that almost every React element must be backed by an Android View. - add clipping information to DrawView, similar to how AbstractDrawCommand has it. This diff implements the latter approach. Reviewed By: ahmedre Differential Revision: D2792375
This commit is contained in:
parent
3d6464d0e1
commit
b321ea98d3
|
@ -13,12 +13,30 @@ import android.graphics.Canvas;
|
|||
|
||||
/* package */ final class DrawView implements DrawCommand {
|
||||
|
||||
/* package */ static DrawView INSTANCE = new DrawView();
|
||||
/* package */ static DrawView INSTANCE = new DrawView(0, 0, 0, 0);
|
||||
|
||||
private DrawView() {}
|
||||
private final float mClipLeft;
|
||||
private final float mClipTop;
|
||||
private final float mClipRight;
|
||||
private final float mClipBottom;
|
||||
|
||||
public DrawView(float clipLeft, float clipTop, float clipRight, float clipBottom) {
|
||||
mClipLeft = clipLeft;
|
||||
mClipTop = clipTop;
|
||||
mClipRight = clipRight;
|
||||
mClipBottom = clipBottom;
|
||||
}
|
||||
|
||||
public boolean clipBoundsMatch(float clipLeft, float clipTop, float clipRight, float clipBottom) {
|
||||
return mClipLeft == clipLeft && mClipTop == clipTop
|
||||
&& mClipRight == clipRight && mClipBottom == clipBottom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(FlatViewGroup parent, Canvas canvas) {
|
||||
canvas.save();
|
||||
canvas.clipRect(mClipLeft, mClipTop, mClipRight, mClipBottom);
|
||||
parent.drawNextChild(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ package com.facebook.react.flat;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.uimanager.CatalystStylesDiffMap;
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.uimanager.ReactProp;
|
||||
|
@ -43,8 +44,8 @@ import com.facebook.react.uimanager.ViewProps;
|
|||
private int mViewTop;
|
||||
private int mViewRight;
|
||||
private int mViewBottom;
|
||||
private boolean mMountsToView;
|
||||
private boolean mBackingViewIsCreated;
|
||||
private @Nullable DrawView mDrawView;
|
||||
private @Nullable DrawBackgroundColor mDrawBackground;
|
||||
private int mMoveToIndexInParent;
|
||||
private boolean mIsOverflowVisible = true;
|
||||
|
@ -253,16 +254,24 @@ import com.facebook.react.uimanager.ViewProps;
|
|||
}
|
||||
|
||||
/* package */ final void forceMountToView() {
|
||||
if (!mMountsToView) {
|
||||
mMountsToView = true;
|
||||
if (mDrawView == null) {
|
||||
mDrawView = DrawView.INSTANCE;
|
||||
if (getParent() != null) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ final DrawView collectDrawView(float left, float top, float right, float bottom) {
|
||||
if (!Assertions.assumeNotNull(mDrawView).clipBoundsMatch(left, top, right, bottom)) {
|
||||
mDrawView = new DrawView(left, top, right, bottom);
|
||||
}
|
||||
|
||||
return mDrawView;
|
||||
}
|
||||
|
||||
/* package */ final boolean mountsToView() {
|
||||
return mMountsToView;
|
||||
return mDrawView != null;
|
||||
}
|
||||
|
||||
/* package */ final boolean isBackingViewCreated() {
|
||||
|
|
|
@ -425,7 +425,11 @@ import com.facebook.react.uimanager.events.EventDispatcher;
|
|||
|
||||
addNativeChild(node);
|
||||
if (!parentIsAndroidView) {
|
||||
mDrawCommands.add(DrawView.INSTANCE);
|
||||
mDrawCommands.add(node.collectDrawView(
|
||||
parentClipLeft,
|
||||
parentClipTop,
|
||||
parentClipRight,
|
||||
parentClipBottom));
|
||||
}
|
||||
|
||||
collectStateForMountableNode(
|
||||
|
|
Loading…
Reference in New Issue