diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostHelper.java new file mode 100644 index 000000000..94cff7823 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostHelper.java @@ -0,0 +1,45 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.react.views.modal; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Point; +import android.view.Display; +import android.view.Surface; +import android.view.WindowManager; + +import com.facebook.infer.annotation.Assertions; + +/** + * Helper class for Modals. + */ +/*package*/ class ModalHostHelper { + + private static final Point MIN_POINT = new Point(); + private static final Point MAX_POINT = new Point(); + + /** + * To get the size of the screen, we use information from the WindowManager and + * default Display. We don't use DisplayMetricsHolder, or Display#getSize() because + * they return values that include the status bar. We only want the values of what + * will actually be shown on screen. + * This should only be called on the native modules/shadow nodes thread. + */ + @TargetApi(16) + public static Point getModalHostSize(Context context) { + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = Assertions.assertNotNull(wm).getDefaultDisplay(); + // getCurrentSizeRange will return the min and max width and height that the window can be + display.getCurrentSizeRange(MIN_POINT, MAX_POINT); + + final int rotation = display.getRotation(); + if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) { + // If we are vertical the width value comes from min width and height comes from max height + return new Point(MIN_POINT.x, MAX_POINT.y); + } else { + // If we are horizontal the width value comes from max width and height comes from min height + return new Point(MAX_POINT.x, MIN_POINT.y); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java new file mode 100644 index 000000000..f1e3b5adf --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java @@ -0,0 +1,38 @@ +/** + * 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.views.modal; + +import android.graphics.Point; + +import com.facebook.csslayout.CSSNode; +import com.facebook.react.uimanager.LayoutShadowNode; + +/** + * We implement the Modal by using an Android Dialog. That will fill the entire window of the + * application. To get layout to work properly, we need to layout all the elements within the + * Modal's inner content view as if they can fill the entire window. To do that, we need to + * explicitly set the styleWidth and styleHeight on the LayoutShadowNode of the child of this node + * to be the window size. This will then cause the children of the Modal to layout as if they can + * fill the window. + */ +class ModalHostShadowNode extends LayoutShadowNode { + + /** + * We need to set the styleWidth and styleHeight of the one child (represented by the + * within the in Modal.js. This needs to fill the entire window. + */ + @Override + public void addChildAt(CSSNode child, int i) { + super.addChildAt(child, i); + Point modalSize = ModalHostHelper.getModalHostSize(getThemedContext()); + child.setStyleWidth(modalSize.x); + child.setStyleHeight(modalSize.y); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java index 3dad7b994..49b6d63e8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java @@ -17,6 +17,7 @@ import android.content.DialogInterface; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.common.MapBuilder; +import com.facebook.react.uimanager.LayoutShadowNode; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.UIManagerModule; @@ -47,6 +48,16 @@ public class ReactModalHostManager extends ViewGroupManager return new ReactModalHostView(reactContext); } + @Override + public LayoutShadowNode createShadowNodeInstance() { + return new ModalHostShadowNode(); + } + + @Override + public Class getShadowNodeClass() { + return ModalHostShadowNode.class; + } + @Override public void onDropViewInstance(ReactModalHostView view) { super.onDropViewInstance(view); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java index 6ac92391e..ce8909bda 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java @@ -17,10 +17,8 @@ import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.graphics.Point; -import android.view.Display; import android.view.KeyEvent; import android.view.MotionEvent; -import android.view.Surface; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -267,8 +265,6 @@ public class ReactModalHostView extends ViewGroup implements LifecycleEventListe static class DialogRootViewGroup extends ReactViewGroup implements RootView { private final JSTouchDispatcher mJSTouchDispatcher = new JSTouchDispatcher(this); - private final Point mMinPoint = new Point(); - private final Point mMaxPoint = new Point(); public DialogRootViewGroup(Context context) { super(context); @@ -282,33 +278,9 @@ public class ReactModalHostView extends ViewGroup implements LifecycleEventListe new Runnable() { @Override public void run() { - // To get the size of the screen, we use information from the WindowManager and - // default Display. We don't use DisplayMetricsHolder, or Display#getSize() because - // they return values that include the status bar. We only want the values of what - // will actually be shown on screen. - Context context = getContext(); - WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - Display display = Assertions.assertNotNull(wm.getDefaultDisplay()); - // getCurrentSizeRange will return the min and max width and height that the window - // can be - display.getCurrentSizeRange(mMinPoint, mMaxPoint); - - int width, height; - int rotation = display.getRotation(); - if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) { - // If we are vertical the width value comes from min width and height comes from - // max height - width = mMinPoint.x; - height = mMaxPoint.y; - } else { - // If we are horizontal the width value comes from max width and height comes from - // min height - width = mMaxPoint.x; - height = mMinPoint.y; - } - + Point modalSize = ModalHostHelper.getModalHostSize(getContext()); ((ReactContext) getContext()).getNativeModule(UIManagerModule.class) - .updateNodeSize(getChildAt(0).getId(), width, height); + .updateNodeSize(getChildAt(0).getId(), modalSize.x, modalSize.y); } }); }