PopupMenu.java revision b933f9c89bbe890ff6753559b83c0ecf236472dd
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.support.v7.widget;
17
18
19import android.content.Context;
20import android.support.annotation.MenuRes;
21import android.support.v7.internal.view.SupportMenuInflater;
22import android.support.v7.internal.view.menu.MenuBuilder;
23import android.support.v7.internal.view.menu.MenuPopupHelper;
24import android.support.v7.internal.view.menu.MenuPresenter;
25import android.support.v7.internal.view.menu.SubMenuBuilder;
26import android.view.Menu;
27import android.view.MenuInflater;
28import android.view.MenuItem;
29import android.view.View;
30
31/**
32 * Static library support version of the framework's {@link android.widget.PopupMenu}.
33 * Used to write apps that run on platforms prior to Android 3.0.  When running
34 * on Android 3.0 or above, this implementation is still used; it does not try
35 * to switch to the framework's implementation. See the framework SDK
36 * documentation for a class overview.
37 */
38public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
39    private Context mContext;
40    private MenuBuilder mMenu;
41    private View mAnchor;
42    private MenuPopupHelper mPopup;
43    private OnMenuItemClickListener mMenuItemClickListener;
44    private OnDismissListener mDismissListener;
45
46    /**
47     * Callback interface used to notify the application that the menu has closed.
48     */
49    public interface OnDismissListener {
50        /**
51         * Called when the associated menu has been dismissed.
52         *
53         * @param menu The PopupMenu that was dismissed.
54         */
55        public void onDismiss(PopupMenu menu);
56    }
57
58    /**
59     * Construct a new PopupMenu.
60     *
61     * @param context Context for the PopupMenu.
62     * @param anchor Anchor view for this popup. The popup will appear below the anchor if there
63     *               is room, or above it if there is not.
64     */
65    public PopupMenu(Context context, View anchor) {
66        mContext = context;
67        mMenu = new MenuBuilder(context);
68        mMenu.setCallback(this);
69        mAnchor = anchor;
70        mPopup = new MenuPopupHelper(context, mMenu, anchor);
71        mPopup.setCallback(this);
72    }
73
74    /**
75     * @return the {@link Menu} associated with this popup. Populate the returned Menu with
76     * items before calling {@link #show()}.
77     *
78     * @see #show()
79     * @see #getMenuInflater()
80     */
81    public Menu getMenu() {
82        return mMenu;
83    }
84
85    /**
86     * @return a {@link MenuInflater} that can be used to inflate menu items from XML into the
87     * menu returned by {@link #getMenu()}.
88     *
89     * @see #getMenu()
90     */
91    public MenuInflater getMenuInflater() {
92        return new SupportMenuInflater(mContext);
93    }
94
95    /**
96     * Inflate a menu resource into this PopupMenu. This is equivalent to calling
97     * popupMenu.getMenuInflater().inflate(menuRes, popupMenu.getMenu()).
98     * @param menuRes Menu resource to inflate
99     */
100    public void inflate(@MenuRes int menuRes) {
101        getMenuInflater().inflate(menuRes, mMenu);
102    }
103
104    /**
105     * Show the menu popup anchored to the view specified during construction.
106     * @see #dismiss()
107     */
108    public void show() {
109        mPopup.show();
110    }
111
112    /**
113     * Dismiss the menu popup.
114     * @see #show()
115     */
116    public void dismiss() {
117        mPopup.dismiss();
118    }
119
120    /**
121     * Set a listener that will be notified when the user selects an item from the menu.
122     *
123     * @param listener Listener to notify
124     */
125    public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
126        mMenuItemClickListener = listener;
127    }
128
129    /**
130     * Set a listener that will be notified when this menu is dismissed.
131     *
132     * @param listener Listener to notify
133     */
134    public void setOnDismissListener(OnDismissListener listener) {
135        mDismissListener = listener;
136    }
137
138    /**
139     * @hide
140     */
141    public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
142        if (mMenuItemClickListener != null) {
143            return mMenuItemClickListener.onMenuItemClick(item);
144        }
145        return false;
146    }
147
148    /**
149     * @hide
150     */
151    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
152        if (mDismissListener != null) {
153            mDismissListener.onDismiss(this);
154        }
155    }
156
157    /**
158     * @hide
159     */
160    public boolean onOpenSubMenu(MenuBuilder subMenu) {
161        if (subMenu == null) return false;
162
163        if (!subMenu.hasVisibleItems()) {
164            return true;
165        }
166
167        // Current menu will be dismissed by the normal helper, submenu will be shown in its place.
168        new MenuPopupHelper(mContext, subMenu, mAnchor).show();
169        return true;
170    }
171
172    /**
173     * @hide
174     */
175    public void onCloseSubMenu(SubMenuBuilder menu) {
176    }
177
178    /**
179     * @hide
180     */
181    public void onMenuModeChange(MenuBuilder menu) {
182    }
183
184    /**
185     * Interface responsible for receiving menu item click events if the items themselves
186     * do not have individual item click listeners.
187     */
188    public interface OnMenuItemClickListener {
189        /**
190         * This method will be invoked when a menu item is clicked if the item itself did
191         * not already handle the event.
192         *
193         * @param item {@link MenuItem} that was clicked
194         * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
195         */
196        public boolean onMenuItemClick(MenuItem item);
197    }
198}