OSDN Git Service

By default, display PopupMenu at Gravity.START and resolve X offset
authorAlan Viverette <alanv@google.com>
Fri, 20 Nov 2015 18:57:15 +0000 (13:57 -0500)
committerAlan Viverette <alanv@google.com>
Fri, 20 Nov 2015 18:57:15 +0000 (13:57 -0500)
Bug: 25801269
Change-Id: I8c8090a59780c131cee2d56b668f1c4e062b8ebe

core/java/com/android/internal/view/menu/MenuPopupHelper.java

index e674ecc..b505ea0 100644 (file)
@@ -38,13 +38,17 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener {
     private View mAnchorView;
     private MenuPopup mPopup;
 
-    private int mDropDownGravity = Gravity.NO_GRAVITY;
+    private int mDropDownGravity = Gravity.START;
     private boolean mForceShowIcon;
     private boolean mShowTitle;
     private Callback mPresenterCallback;
+
     private int mInitXOffset;
     private int mInitYOffset;
 
+    /** Whether the popup has anchor-relative offsets. */
+    private boolean mHasOffsets;
+
     public MenuPopupHelper(Context context, MenuBuilder menu) {
         this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle, 0);
     }
@@ -131,12 +135,31 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener {
 
         mInitXOffset = 0;
         mInitYOffset = 0;
+        mHasOffsets = false;
         mShowTitle = false;
 
         showPopup();
         return true;
     }
 
+    /**
+     * Shows the popup menu and makes a best-effort to anchor it to the
+     * specified (x,y) coordinate relative to the anchor view.
+     * <p>
+     * If the popup's resolved gravity is {@link Gravity#LEFT}, this will
+     * display the popup with its top-left corner at (x,y) relative to the
+     * anchor view. If the resolved gravity is {@link Gravity#RIGHT}, the
+     * popup's top-right corner will be at (x,y).
+     * <p>
+     * If the popup cannot be displayed fully on-screen, this method will
+     * attempt to scroll the anchor view's ancestors and/or offset the popup
+     * such that it may be displayed fully on-screen.
+     *
+     * @param x x coordinate relative to the anchor view
+     * @param y y coordinate relative to the anchor view
+     * @return {@code true} if the popup was shown or was already showing prior
+     *         to calling this method, {@code false} otherwise
+     */
     public boolean tryShow(int x, int y) {
         if (isShowing()) {
             return true;
@@ -148,6 +171,7 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener {
 
         mInitXOffset = x;
         mInitYOffset = y;
+        mHasOffsets = true;
         mShowTitle = true;
 
         showPopup();
@@ -160,9 +184,24 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener {
         mPopup.setCallback(mPresenterCallback);
         mPopup.setForceShowIcon(mForceShowIcon);
         mPopup.setGravity(mDropDownGravity);
-        mPopup.setHorizontalOffset(mInitXOffset);
         mPopup.setShowTitle(mShowTitle);
-        mPopup.setVerticalOffset(mInitYOffset);
+
+        if (mHasOffsets) {
+            // If the resolved drop-down gravity is RIGHT, the popup's right
+            // edge will be aligned with the anchor view. Adjust by the anchor
+            // width such that the top-right corner is at the X offset.
+            final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity,
+                    mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK;
+            final int resolvedXOffset;
+            if (hgrav == Gravity.RIGHT) {
+                resolvedXOffset = mInitXOffset - mAnchorView.getWidth();
+            } else {
+                resolvedXOffset = mInitXOffset;
+            }
+
+            mPopup.setHorizontalOffset(resolvedXOffset);
+            mPopup.setVerticalOffset(mInitYOffset);
+        }
 
         // In order for subclasses of MenuPopupHelper to satisfy the OnDismissedListener interface,
         // we must set the listener to this outer Helper rather than to the inner MenuPopup.