Add a way to dismiss PopupMenu elements
Summary: In native Android apps, like the YouTube app, context menus are closed when the device orientation changes. In React Native apps instead, when having a [PopupMenu](https://developer.android.com/reference/android/widget/PopupMenu.html) open and rotating the device, the PopupMenu is not dismissed and appears in a wrong position on the screen. This PR exposes a `dismissPopupMenu` method to allow the application to dismiss any open PopupMenu: ```(javascript) UIManager.dismissPopupMenu() ``` Closes https://github.com/facebook/react-native/pull/15636 Differential Revision: D6837663 Pulled By: hramos fbshipit-source-id: 7b0f4f04341129ad45c703a50897e17d93651974
This commit is contained in:
parent
6426735e82
commit
353c070be9
|
@ -74,6 +74,7 @@ public class NativeViewHierarchyManager {
|
|||
private final LayoutAnimationController mLayoutAnimator = new LayoutAnimationController();
|
||||
|
||||
private boolean mLayoutAnimationEnabled;
|
||||
private PopupMenu mPopupMenu;
|
||||
|
||||
public NativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
|
||||
this(viewManagers, new RootViewManager());
|
||||
|
@ -731,18 +732,27 @@ public class NativeViewHierarchyManager {
|
|||
error.invoke("Can't display popup. Could not find view with tag " + reactTag);
|
||||
return;
|
||||
}
|
||||
PopupMenu popupMenu = new PopupMenu(getReactContextForView(reactTag), anchor);
|
||||
mPopupMenu = new PopupMenu(getReactContextForView(reactTag), anchor);
|
||||
|
||||
Menu menu = popupMenu.getMenu();
|
||||
Menu menu = mPopupMenu.getMenu();
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
menu.add(Menu.NONE, Menu.NONE, i, items.getString(i));
|
||||
}
|
||||
|
||||
PopupMenuCallbackHandler handler = new PopupMenuCallbackHandler(success);
|
||||
popupMenu.setOnMenuItemClickListener(handler);
|
||||
popupMenu.setOnDismissListener(handler);
|
||||
mPopupMenu.setOnMenuItemClickListener(handler);
|
||||
mPopupMenu.setOnDismissListener(handler);
|
||||
|
||||
popupMenu.show();
|
||||
mPopupMenu.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss the last opened PopupMenu {@link PopupMenu}.
|
||||
*/
|
||||
public void dismissPopupMenu() {
|
||||
if (mPopupMenu != null) {
|
||||
mPopupMenu.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
private static class PopupMenuCallbackHandler implements PopupMenu.OnMenuItemClickListener,
|
||||
|
|
|
@ -802,6 +802,10 @@ public class UIImplementation {
|
|||
mOperationsQueue.enqueueShowPopupMenu(reactTag, items, error, success);
|
||||
}
|
||||
|
||||
public void dismissPopupMenu() {
|
||||
mOperationsQueue.enqueueDismissPopupMenu();
|
||||
}
|
||||
|
||||
public void sendAccessibilityEvent(int tag, int eventType) {
|
||||
mOperationsQueue.enqueueSendAccessibilityEvent(tag, eventType);
|
||||
}
|
||||
|
|
|
@ -600,6 +600,11 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
|
|||
mUIImplementation.showPopupMenu(reactTag, items, error, success);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void dismissPopupMenu() {
|
||||
mUIImplementation.dismissPopupMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled
|
||||
* explicitly in order to avoid regression in existing application written for iOS using this API.
|
||||
|
|
|
@ -285,6 +285,13 @@ public class UIViewOperationQueue {
|
|||
}
|
||||
}
|
||||
|
||||
private final class DismissPopupMenuOperation implements UIOperation {
|
||||
@Override
|
||||
public void execute() {
|
||||
mNativeViewHierarchyManager.dismissPopupMenu();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A spec for animation operations (add/remove)
|
||||
*/
|
||||
|
@ -656,6 +663,10 @@ public class UIViewOperationQueue {
|
|||
mOperations.add(new ShowPopupMenuOperation(reactTag, items, error, success));
|
||||
}
|
||||
|
||||
public void enqueueDismissPopupMenu() {
|
||||
mOperations.add(new DismissPopupMenuOperation());
|
||||
}
|
||||
|
||||
public void enqueueCreateView(
|
||||
ThemedReactContext themedContext,
|
||||
int viewReactTag,
|
||||
|
|
|
@ -33,6 +33,7 @@ import javax.annotation.Nullable;
|
|||
public class ReactToolbarManager extends ViewGroupManager<ReactToolbar> {
|
||||
|
||||
private static final String REACT_CLASS = "ToolbarAndroid";
|
||||
private static final int COMMAND_DISMISS_POPUP_MENUS = 1;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
|
@ -157,6 +158,27 @@ public class ReactToolbarManager extends ViewGroupManager<ReactToolbar> {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Map<String, Integer> getCommandsMap() {
|
||||
return MapBuilder.of("dismissPopupMenus", COMMAND_DISMISS_POPUP_MENUS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveCommand(ReactToolbar view, int commandType, @Nullable ReadableArray args) {
|
||||
switch (commandType) {
|
||||
case COMMAND_DISMISS_POPUP_MENUS: {
|
||||
view.dismissPopupMenus();
|
||||
return;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unsupported command %d received by %s.",
|
||||
commandType,
|
||||
getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
|
||||
private int[] getDefaultContentInsets(Context context) {
|
||||
Resources.Theme theme = context.getTheme();
|
||||
TypedArray toolbarStyle = null;
|
||||
|
|
Loading…
Reference in New Issue