From 82c8c97898c2ba7fbe7e371249354d353b1d4161 Mon Sep 17 00:00:00 2001 From: Andrei Coman Date: Tue, 13 Sep 2016 04:14:43 -0700 Subject: [PATCH] Support orientation change on modals Summary: This automatically changes the size of the modal by listening to dialog size changes and propagating those changes through UIManager. In detail: I've looked into three ways of doing this: 1. Send `onSizeChanged` events/info from the View to the CSSNode directly. This is kinda hacky because you would need to hold a reference to the CSSNode somewhere, either in the View or in the ViewManager. But then you'll have to take care of the lifecycle of the CSSNode, so that you don't update it after it has been dismissed. Not great. 2. The version we went for, is to just update the size of the corresponding CSSNode in the same way we do it for root nodes: we inform the UIManager that the size of the root node has changed, and it will propagate that change, triggering a `dispatchViewUpdates` if none is underway, so that the layout is updated. 3. The other solution we thought of is to treat the Modal as a root view. This would mean rendering an application with the tag of the Modal as the root of the application. That tag would be received by calling some method into UIManager and ReactModalHostManager to create a new RootView, create a Dialog and plop the root view in it. The idea was to maintain the JS API that we now have, but make the implementation more correct (ie. since both RootView and the Modal must deal with touch handling), and could have other benefits (ie. no hacks necessary for making the inspector work on top of modals). However, the change is not trivial and I don't know just how much code would have to be changed to make this work correctly. We might revisit this at a later stage, after we've done more work on having several root views at the same time in the app. Reviewed By: foghina Differential Revision: D3841379 fbshipit-source-id: f5e363e27041b785cf44eb59da04bc789306ddb9 --- .../react/uimanager/UIImplementation.java | 13 +++++++------ .../facebook/react/uimanager/UIManagerModule.java | 6 +++--- .../react/views/modal/ReactModalHostView.java | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java index fd8f76c30..347658583 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java @@ -130,16 +130,17 @@ public class UIImplementation { } /** - * Invoked when native view that corresponds to a root node has its size changed. + * Invoked when native view that corresponds to a root node, or acts as a root view (ie. Modals) + * has its size changed. */ - public void updateRootNodeSize( - int rootViewTag, + public void updateNodeSize( + int nodeViewTag, int newWidth, int newHeight, EventDispatcher eventDispatcher) { - ReactShadowNode rootCSSNode = mShadowNodeRegistry.getNode(rootViewTag); - rootCSSNode.setStyleWidth(newWidth); - rootCSSNode.setStyleHeight(newHeight); + ReactShadowNode cssNode = mShadowNodeRegistry.getNode(nodeViewTag); + cssNode.setStyleWidth(newWidth); + cssNode.setStyleHeight(newHeight); // If we're in the middle of a batch, the change will automatically be dispatched at the end of // the batch. As all batches are executed as a single runnable on the event queue this should diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 5ec09e13c..2cfe95de2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -192,7 +192,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements new Runnable() { @Override public void run() { - updateRootNodeSize(tag, width, height); + updateNodeSize(tag, width, height); } }); } @@ -206,10 +206,10 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements mUIImplementation.removeRootView(rootViewTag); } - private void updateRootNodeSize(int rootViewTag, int newWidth, int newHeight) { + public void updateNodeSize(int nodeViewTag, int newWidth, int newHeight) { getReactApplicationContext().assertOnNativeModulesQueueThread(); - mUIImplementation.updateRootNodeSize(rootViewTag, newWidth, newHeight, mEventDispatcher); + mUIImplementation.updateNodeSize(nodeViewTag, newWidth, newHeight, mEventDispatcher); } @ReactMethod 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 ddf821d45..3d03bd8b3 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 @@ -264,6 +264,21 @@ public class ReactModalHostView extends ViewGroup implements LifecycleEventListe super(context); } + @Override + protected void onSizeChanged(final int w, final int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (getChildCount() > 0) { + ((ReactContext) getContext()).runOnNativeModulesQueueThread( + new Runnable() { + @Override + public void run() { + ((ReactContext) getContext()).getNativeModule(UIManagerModule.class) + .updateNodeSize(getChildAt(0).getId(), w, h); + } + }); + } + } + @Override public boolean onInterceptTouchEvent(MotionEvent event) { mJSTouchDispatcher.handleTouchEvent(event, getEventDispatcher());