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 ...
随机推荐
- EF 6.x、EF Core实现dynamic动态查询和EF Core实现多个上下文实例池你了解多少?
前言 很长一段时间没有写博客了,今天补上一篇吧,偶尔发现不太愿意写博客了,太耗费时间,不过还是在坚持当中,毕竟或许写出来的东西能帮到一些童鞋吧,接下来我们直奔主题.无论是在在EF 6.x还是EF Co ...
- 四柱加强版汉诺塔HanoiTower----是甜蜜还是烦恼
我想很多人第一次学习递归的时候,老师或者书本上可能会举汉诺塔的例子. 但是今天,我们讨论的重点不是简单的汉诺塔算法,而是三柱汉诺塔的延伸.先来看看经典的三柱汉诺塔. 一.三柱汉诺塔(Hanoi_Thr ...
- Tomcat关闭日志输出
tomcat中禁用catalina.out的输出,又可能很大. 1.直接修改catalina.sh文件的输出语句. 在文件中找到以下内容. if [ -z "$CATALINA_OUT&qu ...
- JS实现2048代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- PHP 包含
PHP 包含文件 PHP include 和 require 语句 在 PHP 中,您可以在服务器执行 PHP 文件之前在该文件中插入一个文件的内容. include 和 require 语句用于在执 ...
- Linux下MySQL 数据库的基本操作
1. 创建数据库相关命令: 首先,下载MySQL相关软件包:aptitude install mysql-server/mysql-client MySQL中的root用户类似于Linux下的root ...
- 多线程(四) 实现线程范围内模块之间共享数据及线程间数据独立(Map集合)
多个线程访问共享对象和数据的方式 1.如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,买票系统就可以这么做. 2.如果每个线程执行的代码 ...
- 常用的DDL语句
create database mydb1; 创建一个名称为mydb1的数据库. use db_name; 切换数据库 ; show databases; 查看所有的数据库: select datab ...
- 记住经典的斐波拉契递归和阶乘递归转换为while规律
记住经典的斐波拉契递归和阶乘递归转换为while规律.它为实现更复杂转换提供了启发性思路. # 斐波拉契--树形递归 def fab(n): if n<3: return n return fa ...
- Dynamics CRM2016 Web API之删除
相比之前的增改查,删除就显得简单的多了. 这里的request的type为delete,删除成功的status为204,404则是要删除的记录不存在 var id = 'BAD90A95-7FEA-E ...