Android开发技巧——使用PopupWindow实现弹出菜单
在本文当中,我将会与大家分享一个封装了PopupWindow实现弹出菜单的类,并说明它的实现与使用。
因对界面的需求,android原生的弹出菜单已不能满足我们的需求,自定义菜单成了我们的唯一选择,在本文当中,我将与大家分享如何使用PopupWindow实现弹出菜单。
1.弹出菜单的封装PopMenu
PopupWindow可以说是一个浮动在Activity之上的容器,通常用来显示自定义的视图。比如像自动完成输入框AutoCompleteTextView,它的提示列表就是使用PopupWindow来实现的。下面的抽象类PopMenu封装了使用PopupWindow实现弹出菜单的UI逻辑,但不包括界面布局的设定。
/* * Date: 14-6-13 * Project: Parking Lay-by */ package cn.irains.access.v2.common; import android.content.Context; import android.graphics.drawable.ColorDrawable; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.PopupWindow; import java.util.ArrayList; /** * 对弹出菜单的封装. * Author: msdx (645079761@qq.com) * Time: 14-6-13 下午1:51 */ public abstract class PopMenu { /** * 上下文. */ private Context mContext; /** * 菜单项 */ private ArrayList<Item> mItemList; /** * 列表适配器. */ private ArrayAdapter<Item> mAdapter; /** * 菜单选择监听. */ private OnItemSelectedListener mListener; /** * 列表. */ private ListView mListView; /** * 弹出窗口. */ private PopupWindow mPopupWindow; public PopMenu(Context context) { mContext = context; mItemList = new ArrayList<Item>(2); View view = onCreateView(context); view.setFocusableInTouchMode(true); mAdapter = onCreateAdapter(context, mItemList); mListView = findListView(view); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Item item = mAdapter.getItem(position); if (mListener != null) { mListener.selected(view, item, position); } mPopupWindow.dismiss(); } }); view.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_MENU && mPopupWindow.isShowing()) { mPopupWindow.dismiss(); return true; } return false; } }); mPopupWindow = new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true); mPopupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000)); } /** * 菜单的界面视图. * * @param context * @return */ protected abstract View onCreateView(Context context); /** * 菜单界面视图中的列表. * * @param view * @return */ protected abstract ListView findListView(View view); /** * 菜单列表中的适配器. * * @param context * @param itemList 表示所有菜单项. * @return */ protected abstract ArrayAdapter<Item> onCreateAdapter(Context context, ArrayList<Item> itemList); /** * 添加菜单项. * * @param text 菜单项文字内容. * @param id 菜单项的ID */ public void addItem(String text, int id) { mItemList.add(new Item(text, id)); mAdapter.notifyDataSetChanged(); } /** * 添加菜单项. * * @param resId 菜单项文字内容的资源ID * @param id 菜单项的ID. */ public void addItem(int resId, int id) { addItem(mContext.getString(resId), id); } /** * 作为指定View的下拉控制显示. * * @param parent 所指定的View */ public void showAsDropDown(View parent) { mPopupWindow.showAsDropDown(parent); } /** * 隐藏菜单. */ public void dismiss() { mPopupWindow.dismiss(); } /** * 设置菜单选择监听. * * @param listener 监听器. */ public void setOnItemSelectedListener(OnItemSelectedListener listener) { mListener = listener; } /** * 当前菜单是否正在显示. * * @return */ public boolean isShowing() { return mPopupWindow.isShowing(); } /** * 菜单项. */ public static class Item { public String text; public int id; public Item(String text, int id) { this.text = text; this.id = id; } @Override public String toString() { return text; } } /** * 菜单项选择监听接口. */ public static interface OnItemSelectedListener { /** * 菜单被选择时的回调接口. * * @param view 被选择的内容的View. * @param item 被选择的菜单项. * @param position 被选择的位置. */ public void selected(View view, Item item, int position); } }
这里面有三个抽象方法,第一个是onCreateView(Context context),在这里需要实现并返回我们的弹出菜单的这个view,然后才能装载到PopupWindow当中并显示出来。
第二个方法是findListView(View view)。这是因为我们的菜单通常是一个列表,然后点击去选择列表的某一项,所以这里需要返回一个ListView对象,用来装载我们的菜单项。
第三个方法是onCreateAdapter,即listview的适配器。
在这个类中,还封装了一个内部类Item:
/** * 菜单项. */ public static class Item { public String text; public int id; public Item(String text, int id) { this.text = text; this.id = id; } @Override public String toString() { return text; } }
它用来表示我们的菜单项,text是显示在菜单当中的文本信息,id表示菜单项的ID。
在该抽象类中还定义了一个接口OnItemSelectedListener,是在菜单项被点击时的回调接口。关于它的说明见注释,这是我在这个博客里目前为止注释写得最详细的一个类了。
2.PopMenu的使用
首先继承PopMenu并实现抽象方法:
/* * Date: 14-9-2 * Project: Access-Control-V2 */ package cn.irains.access.v2.usermanager; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.widget.ArrayAdapter; import android.widget.ListView; import java.util.ArrayList; import cn.irains.access.v2.R; import cn.irains.access.v2.common.PopMenu; /** * Author: msdx (645079761@qq.com) * Time: 14-9-2 上午8:56 */ public class UserMenu extends PopMenu { public UserMenu(Context context) { super(context); } @Override protected ListView findListView(View view) { return (ListView) view.findViewById(R.id.menu_listview); } @Override protected View onCreateView(Context context) { View view = LayoutInflater.from(context).inflate(R.layout.menu_user, null); return view; } @Override protected ArrayAdapter<Item> onCreateAdapter(Context context, ArrayList<Item> items) { return new ArrayAdapter<Item>(context, R.layout.item_menu_user, items); } }
ListView的宽度,如果不写死的话,默认是宽度填充满父控件的,就像ViewPager默认高度填满父控件一样。如果想让ListView的宽度适配内容,则需要重写一下。参考前面的文章(Android开发技巧——ViewPager衍生出来的2个类),代码如下:
/* * Date: 14-9-2 * Project: Access-Control-V2 */ package cn.irains.access.v2.common; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.widget.ListView; /** * 宽度适配内容的ListView. * Author: msdx (645079761@qq.com) * Time: 14-9-2 下午5:14 */ public class WrapWidthListView extends ListView { public WrapWidthListView(Context context) { super(context); } public WrapWidthListView(Context context, AttributeSet attrs) { super(context, attrs); } public WrapWidthListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), heightMeasureSpec); int w = child.getMeasuredWidth(); if (w > width) width = w; } widthMeasureSpec = MeasureSpec.makeMeasureSpec(width + getPaddingLeft() + getPaddingRight(), MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }
弹出菜单的布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:paddingRight="@dimen/pop_menu_padding" android:orientation="vertical" android:layout_height="wrap_content"> <ImageView android:id="@+id/head" android:src="@drawable/pop_menu_head" android:layout_gravity="right" android:layout_width="wrap_content" android:contentDescription="@null" android:layout_marginRight="18dp" android:layout_height="wrap_content"/> <cn.irains.access.v2.common.WrapWidthListView android:id="@+id/menu_listview" android:padding="6dp" android:focusable="true" android:layout_width="wrap_content" android:background="@drawable/pop_menu_body" android:cacheColorHint="@android:color/transparent" android:layout_height="wrap_content"/> </LinearLayout>
其中的ImageView的照片是一个黑色三角图案。这个等在最后我发一下效果图就明白了。ListView背景是一张黑色图片。
接下来是item的布局,只是一个TextView,代码如下:
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:textSize="@dimen/text_size_large" android:textColor="@color/text_choice_selector" android:background="@drawable/item_choice_selector" android:gravity="center" android:layout_gravity="center" android:paddingLeft="20dp" android:paddingTop="6dp" android:singleLine="true" android:paddingBottom="6dp" android:paddingRight="20dp" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
使用代码如下:
private static final int USER_SEARCH = 0; private static final int USER_ADD = 1; private UserMenu mMenu; private void initMenu() { mMenu = new UserMenu(context); mMenu.addItem(R.string.user_search, USER_SEARCH); mMenu.addItem(R.string.user_add, USER_ADD); mMenu.setOnItemSelectedListener(new PopMenu.OnItemSelectedListener() { @Override public void selected(View view, PopMenu.Item item, int position) { switch (item.id) { case USER_SEARCH: startActivity(new Intent(getActivity(), UserSearchActivity.class)); break; case USER_ADD: startActivity(new Intent(getActivity(), UserAddActivity.class)); break; } } }); }
在activity的onCreate或fragment中的onCreateView中初始化menu代码,然后需要显示时调用mMenu.showAsDropDown(view);它就作为view的下拉菜单显示了。效果如下:
本文原创,转载请注明出处:http://blog.csdn.net/maosidiaoxian/article/details/39178167
Android开发技巧——使用PopupWindow实现弹出菜单的更多相关文章
- Android 使用PopupWindow实现弹出菜单
在本文当中,我将会与大家分享一个封装了PopupWindow实现弹出菜单的类,并说明它的实现与使用. 因对界面的需求,android原生的弹出菜单已不能满足我们的需求,自定义菜单成了我们的唯一选择,在 ...
- 如何利用PopupWindow实现弹出菜单并解决焦点获取以及与软键盘冲突问题
如何利用PopupWindow实现弹出菜单并解决焦点获取以及与软键盘冲突问题 如何利用PopupWindow实现弹出菜单并解决焦点获取以及与软键盘冲突问题 在android中有时候可能要实现一个底部弹 ...
- 用PopupWindow实现弹出菜单(弹出的菜单采用自定义布局)
用PopupWindow实现弹出菜单是一个比较好的方式.当然我们还有一个类PopupMenu也能实现弹出菜单,但那个太过于局限了,所以不是很推荐. 这个实例的效果是这样的:点击按钮后,一个菜 ...
- Android ListView两种长按弹出菜单方式
转自:http://www.cnblogs.com/yejiurui/p/3247527.html package com.wyl.download_demo; import java.util.Ar ...
- Android开发技巧——实现可复用的ActionSheet菜单
在上一篇<Android开发技巧--使用Dialog实现仿QQ的ActionSheet菜单>中,讲了这种菜单的实现过程,接下来将把它改成一个可复用的控件库. 本文原创,转载请注明出处: h ...
- Android开发实战之底部Dialog弹出效果
在Android开发中,有很多情况下我们需要使用到对话框,遗憾的是,安卓自带的对话框样式不能满足我们实际的需要,所以往往需要我们自定义对话框,具体做法:写一个对话框继承自Dialog实现他的一个构造方 ...
- Android基础之响应Menu键弹出菜单Demo
对于Android我也不是很熟悉,只是学习一些基本内容就OK.所以写的内容也很简单.本Demo要实现的效果就点击Menu键将弹出一个菜单并响应点击菜单项事件. 一.废话少说直接上代码.其实就是重写两个 ...
- Android开发禁止首次进入activity弹出软键盘,限制屏幕只能竖屏或者横屏展示
作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 只需在在Manifest.xml中设定activity的属性为: android:windowSoft ...
- <转>Android开发使输入框点击弹出日期选择对话框的方法
非常简单直接上代码: 转自:http://blog.sina.com.cn/s/blog_4ac1b5f60102vgnx.html final EditText et1=(EditText)find ...
随机推荐
- YOLO2:实时目标检测视频教程,视频演示, Android Demo ,开源教学项目,论文。
实时目标检测和分类 GIF 图: 视频截图: 论文: https://arxiv.org/pdf/1506.02640.pdf https://arxiv.org/pdf/1612.08242.pdf ...
- jvm(一):总体概述
我们首先来了解一下jdk,jre,jvm的之间的关系 jvm用于运行字节码,如果我们仅仅用于运行java程序,仅部署jre即可,如果我们需要进行java开发则需要jdk环境 java结构内容: jav ...
- prop与attr的区别
与prop一样attr也可以用来获取与设置元素的属性. 区别在于,对于自定义属性和选中属性的处理. 选中属性指的是 checked,selected 这2种属性 1. 对于自定义属性 attr能够获取 ...
- WEB中间件--Jboss未授权访问,
1,Jboss未授权访问部署木马 发现存在Jboss默认页面,点进控制页 点击 Jboss.deployment 进入应用部署页面 也可以直接输入此URL进入 http://www.ctfswiki. ...
- Java HashMap的扩容
最近博主参加面试,发现自己对于Java的HashMap的扩容过程理解不足,故最近在此进行总结. 首先说明博主德Java为1.8版本 HashMap中的变量 首先要了解HashMap的扩容过程,我们就得 ...
- angular 路由的引用
使用angular路由 遇到的坑. 使用cmd 安装好node.js 安装成功 输入node -v 能查看版本说明安装成功 搭建angular项目输入命令 npm install -g angu ...
- Python 头部 #!/usr/bin/python 和 #!/usr/bin/env 的区别
这个网址 https://www.cnblogs.com/scofi/p/4867851.html 讲述了Python 头部 #!/usr/bin/python 和 #!/usr/bin/env 的区 ...
- 容器化现有ASP.NET MVC 5应用
.NET Core的出现使得ASP.NET应用在Linux环境下使用变得更加普及.而配合上Docker容器,令ASP.NET应用的布署与管理也变得更加方便.在新的项目中运用ASP.NET Core无可 ...
- jQuery 遍历 – 后代
后代是子.孙.曾孙等等. 通过 jQuery,您能够向下遍历 DOM 树,以查找元素的后代. 向下遍历 DOM 树 下面是两个用于向下遍历 DOM 树的 jQuery 方法: children() f ...
- Linux(十七)动态监控进程
17.1 介绍 top与ps命令很相似.它们都用来显示正在执行的进程.top与ps最大的不同之处,在于top在执行一段时间可以更新正在运行的进程 17.2 语法 top [选项] 常用选项 ...