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
This commit is contained in:
Andrei Coman 2016-09-13 04:14:43 -07:00 committed by Facebook Github Bot 4
parent 178407da40
commit 82c8c97898
3 changed files with 25 additions and 9 deletions

View File

@ -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

View File

@ -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

View File

@ -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());