Add mechanism to enforce certain Views always being visible in the View hierarchy

Summary:
See comments in ReactClippingProhibitedView for details and motivation behind this new feature.

You may have a View class inherit from the ReactClippingProhibitedView interface in order to enable this feature for instances of that View type.

This can be added to Views that should /never/ be clipped from the View hierarchy - namely, TTRC components or other telemetry components that always need to be rendered in order for some feature to function.

Changelog: [Added] Opt-in mechanism to allow native Android Views to be marked as "not clippable", soft exceptions will be logged if these Views are clipped from the View hierarchy

Reviewed By: sshic

Differential Revision: D29472439

fbshipit-source-id: b3be53df836b452aed5dc40514ff585ce0ad812b
This commit is contained in:
Joshua Gross
2021-06-30 10:38:41 -07:00
committed by Facebook GitHub Bot
parent e6b9508f12
commit 34903ba418
3 changed files with 74 additions and 2 deletions
@@ -49,6 +49,7 @@ import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.IllegalViewOperationException;
import com.facebook.react.uimanager.JSTouchDispatcher;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.ReactClippingProhibitedView;
import com.facebook.react.uimanager.ReactRoot;
import com.facebook.react.uimanager.RootView;
import com.facebook.react.uimanager.RootViewUtil;
@@ -329,9 +330,29 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
}
@Override
public void onViewAdded(View child) {
public void onViewAdded(final View child) {
super.onViewAdded(child);
// See comments in {@code ReactRootViewProhibitedChildView} for why we want this mechanism.
if (child instanceof ReactClippingProhibitedView) {
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!child.isShown()) {
ReactSoftException.logSoftException(
TAG,
new IllegalViewOperationException(
"A view was illegally added as a child of a ReactRootView. "
+ "This View should not be a direct child of a ReactRootView, because it is not visible and will never be reachable. Child: "
+ child.getClass().getCanonicalName().toString()
+ " child ID: "
+ child.getId()));
}
}
});
}
if (mShouldLogContentAppeared) {
mShouldLogContentAppeared = false;