`

Android开发技巧——使用PopupWindow实现弹出菜单

 
阅读更多

转于:http://blog.csdn.net/maosidiaoxian/article/details/39178167

 

-----------------------------------------------------------------------------------------

在本文当中,我将会与大家分享一个封装了PopupWindow实现弹出菜单的类,并说明它的实现与使用。

因对界面的需求,android原生的弹出菜单已不能满足我们的需求,自定义菜单成了我们的唯一选择,在本文当中,我将与大家分享如何使用PopupWindow实现弹出菜单。

1.弹出菜单的封装PopMenu

PopupWindow可以说是一个浮动在Activity之上的容器,通常用来显示自定义的视图。比如像自动完成输入框AutoCompleteTextView,它的提示列表就是使用PopupWindow来实现的。下面的抽象类PopMenu封装了使用PopupWindow实现弹出菜单的UI逻辑,但不包括界面布局的设定。

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /* 
  2.  * Date: 14-6-13 
  3.  * Project: Parking Lay-by 
  4.  */  
  5. package cn.irains.access.v2.common;  
  6.   
  7. import android.content.Context;  
  8. import android.graphics.drawable.ColorDrawable;  
  9. import android.view.KeyEvent;  
  10. import android.view.View;  
  11. import android.view.ViewGroup;  
  12. import android.widget.AdapterView;  
  13. import android.widget.ArrayAdapter;  
  14. import android.widget.ListView;  
  15. import android.widget.PopupWindow;  
  16.   
  17. import java.util.ArrayList;  
  18.   
  19. /** 
  20.  * 对弹出菜单的封装. 
  21.  * Author: msdx (645079761@qq.com) 
  22.  * Time: 14-6-13 下午1:51 
  23.  */  
  24. public abstract class PopMenu {  
  25.     /** 
  26.      * 上下文. 
  27.      */  
  28.     private Context mContext;  
  29.     /** 
  30.      * 菜单项 
  31.      */  
  32.     private ArrayList<Item> mItemList;  
  33.     /** 
  34.      * 列表适配器. 
  35.      */  
  36.     private ArrayAdapter<Item> mAdapter;  
  37.     /** 
  38.      * 菜单选择监听. 
  39.      */  
  40.     private OnItemSelectedListener mListener;  
  41.     /** 
  42.      * 列表. 
  43.      */  
  44.     private ListView mListView;  
  45.     /** 
  46.      * 弹出窗口. 
  47.      */  
  48.     private PopupWindow mPopupWindow;  
  49.   
  50.     public PopMenu(Context context) {  
  51.         mContext = context;  
  52.         mItemList = new ArrayList<Item>(2);  
  53.         View view = onCreateView(context);  
  54.         view.setFocusableInTouchMode(true);  
  55.         mAdapter = onCreateAdapter(context, mItemList);  
  56.         mListView = findListView(view);  
  57.         mListView.setAdapter(mAdapter);  
  58.         mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
  59.             @Override  
  60.             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {  
  61.                 Item item = mAdapter.getItem(position);  
  62.                 if (mListener != null) {  
  63.                     mListener.selected(view, item, position);  
  64.                 }  
  65.                 mPopupWindow.dismiss();  
  66.             }  
  67.         });  
  68.         view.setOnKeyListener(new View.OnKeyListener() {  
  69.             @Override  
  70.             public boolean onKey(View v, int keyCode, KeyEvent event) {  
  71.                 if (keyCode == KeyEvent.KEYCODE_MENU && mPopupWindow.isShowing()) {  
  72.                     mPopupWindow.dismiss();  
  73.                     return true;  
  74.                 }  
  75.                 return false;  
  76.             }  
  77.         });  
  78.         mPopupWindow = new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);  
  79.         mPopupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));  
  80.     }  
  81.   
  82.     /** 
  83.      * 菜单的界面视图. 
  84.      * 
  85.      * @param context 
  86.      * @return 
  87.      */  
  88.     protected abstract View onCreateView(Context context);  
  89.   
  90.     /** 
  91.      * 菜单界面视图中的列表. 
  92.      * 
  93.      * @param view 
  94.      * @return 
  95.      */  
  96.     protected abstract ListView findListView(View view);  
  97.   
  98.     /** 
  99.      * 菜单列表中的适配器. 
  100.      * 
  101.      * @param context 
  102.      * @param itemList 表示所有菜单项. 
  103.      * @return 
  104.      */  
  105.     protected abstract ArrayAdapter<Item> onCreateAdapter(Context context, ArrayList<Item> itemList);  
  106.   
  107.     /** 
  108.      * 添加菜单项. 
  109.      * 
  110.      * @param text 菜单项文字内容. 
  111.      * @param id   菜单项的ID 
  112.      */  
  113.     public void addItem(String text, int id) {  
  114.         mItemList.add(new Item(text, id));  
  115.         mAdapter.notifyDataSetChanged();  
  116.     }  
  117.   
  118.     /** 
  119.      * 添加菜单项. 
  120.      * 
  121.      * @param resId 菜单项文字内容的资源ID 
  122.      * @param id    菜单项的ID. 
  123.      */  
  124.     public void addItem(int resId, int id) {  
  125.         addItem(mContext.getString(resId), id);  
  126.     }  
  127.   
  128.     /** 
  129.      * 作为指定View的下拉控制显示. 
  130.      * 
  131.      * @param parent 所指定的View 
  132.      */  
  133.     public void showAsDropDown(View parent) {  
  134.         mPopupWindow.showAsDropDown(parent);  
  135.     }  
  136.   
  137.     /** 
  138.      * 隐藏菜单. 
  139.      */  
  140.     public void dismiss() {  
  141.         mPopupWindow.dismiss();  
  142.     }  
  143.   
  144.     /** 
  145.      * 设置菜单选择监听. 
  146.      * 
  147.      * @param listener 监听器. 
  148.      */  
  149.     public void setOnItemSelectedListener(OnItemSelectedListener listener) {  
  150.         mListener = listener;  
  151.     }  
  152.   
  153.     /** 
  154.      * 当前菜单是否正在显示. 
  155.      * 
  156.      * @return 
  157.      */  
  158.     public boolean isShowing() {  
  159.         return mPopupWindow.isShowing();  
  160.     }  
  161.   
  162.     /** 
  163.      * 菜单项. 
  164.      */  
  165.     public static class Item {  
  166.         public String text;  
  167.         public int id;  
  168.   
  169.         public Item(String text, int id) {  
  170.             this.text = text;  
  171.             this.id = id;  
  172.         }  
  173.   
  174.         @Override  
  175.         public String toString() {  
  176.             return text;  
  177.         }  
  178.     }  
  179.   
  180.     /** 
  181.      * 菜单项选择监听接口. 
  182.      */  
  183.     public static interface OnItemSelectedListener {  
  184.         /** 
  185.          * 菜单被选择时的回调接口. 
  186.          * 
  187.          * @param view     被选择的内容的View. 
  188.          * @param item     被选择的菜单项. 
  189.          * @param position 被选择的位置. 
  190.          */  
  191.         public void selected(View view, Item item, int position);  
  192.     }  
  193. }  


这里面有三个抽象方法,第一个是onCreateView(Context context),在这里需要实现并返回我们的弹出菜单的这个view,然后才能装载到PopupWindow当中并显示出来。

 

第二个方法是findListView(View view)。这是因为我们的菜单通常是一个列表,然后点击去选择列表的某一项,所以这里需要返回一个ListView对象,用来装载我们的菜单项。

第三个方法是onCreateAdapter,即listview的适配器。

在这个类中,还封装了一个内部类Item:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /** 
  2.  * 菜单项. 
  3.  */  
  4. public static class Item {  
  5.     public String text;  
  6.     public int id;  
  7.   
  8.     public Item(String text, int id) {  
  9.         this.text = text;  
  10.         this.id = id;  
  11.     }  
  12.   
  13.     @Override  
  14.     public String toString() {  
  15.         return text;  
  16.     }  
  17. }  

它用来表示我们的菜单项,text是显示在菜单当中的文本信息,id表示菜单项的ID。

 

在该抽象类中还定义了一个接口OnItemSelectedListener,是在菜单项被点击时的回调接口。关于它的说明见注释,这是我在这个博客里目前为止注释写得最详细的一个类了。

2.PopMenu的使用

首先继承PopMenu并实现抽象方法:

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /* 
  2.  * Date: 14-9-2 
  3.  * Project: Access-Control-V2 
  4.  */  
  5. package cn.irains.access.v2.usermanager;  
  6.   
  7. import android.content.Context;  
  8. import android.view.LayoutInflater;  
  9. import android.view.View;  
  10. import android.widget.ArrayAdapter;  
  11. import android.widget.ListView;  
  12.   
  13. import java.util.ArrayList;  
  14.   
  15. import cn.irains.access.v2.R;  
  16. import cn.irains.access.v2.common.PopMenu;  
  17.   
  18. /** 
  19.  * Author: msdx (645079761@qq.com) 
  20.  * Time: 14-9-2 上午8:56 
  21.  */  
  22. public class UserMenu extends PopMenu {  
  23.     public UserMenu(Context context) {  
  24.         super(context);  
  25.     }  
  26.   
  27.     @Override  
  28.     protected ListView findListView(View view) {  
  29.         return (ListView) view.findViewById(R.id.menu_listview);  
  30.     }  
  31.   
  32.     @Override  
  33.     protected View onCreateView(Context context) {  
  34.         View view = LayoutInflater.from(context).inflate(R.layout.menu_user, null);  
  35.         return view;  
  36.     }  
  37.   
  38.     @Override  
  39.     protected ArrayAdapter<Item> onCreateAdapter(Context context, ArrayList<Item> items) {  
  40.         return new ArrayAdapter<Item>(context, R.layout.item_menu_user, items);  
  41.     }  
  42. }  


ListView的宽度,如果不写死的话,默认是宽度填充满父控件的,就像ViewPager默认高度填满父控件一样。如果想让ListView的宽度适配内容,则需要重写一下。参考前面的文章(Android开发技巧——ViewPager衍生出来的2个类),代码如下:

 

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /* 
  2.  * Date: 14-9-2 
  3.  * Project: Access-Control-V2 
  4.  */  
  5. package cn.irains.access.v2.common;  
  6.   
  7. import android.content.Context;  
  8. import android.util.AttributeSet;  
  9. import android.view.View;  
  10. import android.widget.ListView;  
  11.   
  12. /** 
  13.  * 宽度适配内容的ListView. 
  14.  * Author: msdx (645079761@qq.com) 
  15.  * Time: 14-9-2 下午5:14 
  16.  */  
  17. public class WrapWidthListView extends ListView {  
  18.   
  19.     public WrapWidthListView(Context context) {  
  20.         super(context);  
  21.     }  
  22.   
  23.     public WrapWidthListView(Context context, AttributeSet attrs) {  
  24.         super(context, attrs);  
  25.     }  
  26.   
  27.     public WrapWidthListView(Context context, AttributeSet attrs, int defStyle) {  
  28.         super(context, attrs, defStyle);  
  29.     }  
  30.   
  31.     @Override  
  32.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  33.         int width = 0;  
  34.         for (int i = 0; i < getChildCount(); i++) {  
  35.             View child = getChildAt(i);  
  36.             child.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), heightMeasureSpec);  
  37.             int w = child.getMeasuredWidth();  
  38.             if (w > width) width = w;  
  39.         }  
  40.   
  41.         widthMeasureSpec = MeasureSpec.makeMeasureSpec(width + getPaddingLeft() + getPaddingRight(), MeasureSpec.EXACTLY);  
  42.   
  43.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  44.     }  
  45. }  


弹出菜单的布局文件如下:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.               android:layout_width="wrap_content"  
  4.               android:paddingRight="@dimen/pop_menu_padding"  
  5.               android:orientation="vertical"  
  6.               android:layout_height="wrap_content">  
  7.   
  8.     <ImageView  
  9.         android:id="@+id/head"  
  10.         android:src="@drawable/pop_menu_head"  
  11.         android:layout_gravity="right"  
  12.         android:layout_width="wrap_content"  
  13.         android:contentDescription="@null"  
  14.         android:layout_marginRight="18dp"  
  15.         android:layout_height="wrap_content"/>  
  16.   
  17.     <cn.irains.access.v2.common.WrapWidthListView  
  18.         android:id="@+id/menu_listview"  
  19.         android:padding="6dp"  
  20.         android:focusable="true"  
  21.         android:layout_width="wrap_content"  
  22.         android:background="@drawable/pop_menu_body"  
  23.         android:cacheColorHint="@android:color/transparent"  
  24.         android:layout_height="wrap_content"/>  
  25. </LinearLayout>  

其中的ImageView的照片是一个黑色三角图案。这个等在最后我发一下效果图就明白了。ListView背景是一张黑色图片。

 

接下来是item的布局,只是一个TextView,代码如下:

 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3. <TextView xmlns:android="http://schemas.android.com/apk/res/android"  
  4.           android:textSize="@dimen/text_size_large"  
  5.           android:textColor="@color/text_choice_selector"  
  6.           android:background="@drawable/item_choice_selector"  
  7.           android:gravity="center"  
  8.           android:layout_gravity="center"  
  9.           android:paddingLeft="20dp"  
  10.           android:paddingTop="6dp"  
  11.           android:singleLine="true"  
  12.           android:paddingBottom="6dp"  
  13.           android:paddingRight="20dp"  
  14.           android:layout_width="wrap_content"  
  15.           android:layout_height="wrap_content"/>  


使用代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1.     private static final int USER_SEARCH = 0;  
  2.     private static final int USER_ADD = 1;  
  3.     private UserMenu mMenu;  
  4.       
  5.       
  6.     private void initMenu() {  
  7.         mMenu = new UserMenu(context);  
  8.         mMenu.addItem(R.string.user_search, USER_SEARCH);  
  9.         mMenu.addItem(R.string.user_add, USER_ADD);  
  10.         mMenu.setOnItemSelectedListener(new PopMenu.OnItemSelectedListener() {  
  11.             @Override  
  12.             public void selected(View view, PopMenu.Item item, int position) {  
  13.                 switch (item.id) {  
  14.                     case USER_SEARCH:  
  15.                         startActivity(new Intent(getActivity(), UserSearchActivity.class));  
  16.                         break;  
  17.                     case USER_ADD:  
  18.                         startActivity(new Intent(getActivity(), UserAddActivity.class));  
  19.                         break;  
  20.                 }  
  21.             }  
  22.         });  
  23.     }  

在activity的onCreate或fragment中的onCreateView中初始化menu代码,然后需要显示时调用mMenu.showAsDropDown(view);它就作为view的下拉菜单显示了。效果如下:

 

 

分享到:
评论

相关推荐

    安卓Android源码——用PopupWindow实现弹出菜单.zip

    本项目"安卓Android源码——用PopupWindow实现弹出菜单.zip"显然是一个演示如何使用`PopupWindow`来构建弹出菜单的实例。下面我们将深入探讨`PopupWindow`的关键知识点。 首先,`PopupWindow` 是 Android SDK 提供...

    Android源码——PopupWindow实现弹出菜单.zip

    本资料包"Android源码——PopupWindow实现弹出菜单.zip"主要聚焦于如何利用`PopupWindow`来创建自定义的弹出菜单。下面将详细介绍`PopupWindow`的基本概念、工作原理以及实现弹出菜单的关键步骤。 `PopupWindow` 是...

    安卓Android源码——Android之用PopupWindow实现弹出菜单.zip

    这个压缩包“安卓Android源码——Android之用PopupWindow实现弹出菜单.zip”显然是为了演示如何使用`PopupWindow`来构建弹出菜单。现在,我们将深入探讨`PopupWindow`的使用及其背后的原理。 `PopupWindow` 是 ...

    安卓Android源码——精典源码之之用PopupWindow实现弹出菜单.zip

    这个压缩包“安卓Android源码——精典源码之之用PopupWindow实现弹出菜单.zip”显然是提供了一个使用`PopupWindow`创建弹出菜单的实例代码。下面我们将深入探讨`PopupWindow`的工作原理及其在实际应用中的使用方法。...

    安卓Android源码——多级PopupWindow的小demo.zip

    在安卓开发中,`PopupWindow` 是一个非常实用的组件,它允许开发者在屏幕上弹出一个浮动窗口,常用于下拉菜单、浮层提示等场景。这个“安卓Android源码——多级PopupWindow的小demo.zip”文件提供了一个展示如何实现...

    安卓Android源码——仿微信popupwindow.zip

    这意味着开发者可能已经对微信中弹出菜单或者提示框的交互方式进行了研究,并尝试通过源码的形式复现这一功能。 【标签解析】 "android" 和 "安卓" 标签明确指出这是关于Android开发的内容;"源码" 标签则告诉我们...

    安卓Android源码——自动判断位置的弹出菜单.zip

    这个压缩包文件“安卓Android源码——自动判断位置的弹出菜单.zip”包含了一个实例,演示了如何在Android应用中创建这样一个功能。通过分析其中的源码和图像资源,我们可以学习到以下关键知识点: 1. PopupWindow:...

    安卓Android源码——PopupWindow下拉列表.rar

    在安卓开发中,`PopupWindow` 是一个非常重要的组件,常用于实现各种弹出式界面,比如下拉列表、菜单等。本资源“安卓Android源码——PopupWindow下拉列表.rar”显然提供了一些关于如何使用`PopupWindow`来创建下拉...

    Android:PowerPopMenu——加强版的PopupWindow菜单

    总的来说,PowerPopMenu是一个强大且易用的Android库,它极大地扩展了PopupWindow的功能,使得开发者能够快速构建出美观且功能丰富的弹出菜单。无论是在小型项目还是大型应用中,PowerPopMenu都能为Android应用的...

    安卓Android源码——PopupWindow模仿UC底部Menu.rar

    在安卓开发中,`PopupWindow` 是一个非常重要的组件,常用于实现各种弹出式界面,比如下拉菜单、提示框等。这个压缩包“安卓Android源码——PopupWindow模仿UC底部Menu.rar”显然是一个示例项目,它展示了如何利用`...

    博客《 PopUpWindow使用详解(一)——基本使用》对应源码

    在Android开发中,PopupWindow是一个非常实用的组件,它能够创建一种浮现在当前Activity之上的窗口,用于显示临时的信息或者菜单。这篇博客《PopUpWindow使用详解(一)——基本使用》及其源码,旨在帮助开发者更好地...

    安卓Android源码——PopupWindow模仿UC底部Menu.zip

    在安卓开发中,`PopupWindow` 是一个非常实用的组件,它可以用来创建浮动窗口,类似于弹出菜单或者对话框。这个压缩包中的示例代码,是关于如何使用 `PopupWindow` 模仿UC浏览器底部的菜单设计。我们将深入探讨 `...

    Android-Android仿Qzone底部导航栏加号弹出菜单

    4. **弹出菜单实现**:有两种常见的方法来实现弹出菜单——PopupMenu或DialogFragment。 - **PopupMenu**:一个轻量级的弹出菜单,可以直接附加到View上。在上面的示例中,`showPopupMenu()`方法可以这样实现: ...

    Android源码——实现半透明的popupwindow的源码.zip

    在Android开发中,PopupWindow是一个非常实用的组件,它能够以弹出窗口的形式展示内容,通常用于实现下拉菜单、提示信息等效果。本资源"Android源码——实现半透明的popupwindow的源码.zip"提供了如何创建一个半透明...

    安卓Android源码——精典源码之多级PopupWindow的小demo.zip

    在安卓开发中,`PopupWindow` 是一个非常实用的组件,它允许我们在主界面上创建一个弹出式视图,可以用于实现下拉菜单、浮动提示等效果。在这个"安卓Android源码——经典源码之多级PopupWindow的小demo.zip"中,我们...

Global site tag (gtag.js) - Google Analytics