在本文当中,我将会与大家分享一个封装了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>();
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 = ;
for (int i = ; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(MeasureSpec.makeMeasureSpec(, 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 = ;
    private static final int USER_ADD = ;
    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的下拉菜单显示了。效果如下:

Android 使用PopupWindow实现弹出菜单的更多相关文章

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

    在本文当中,我将会与大家分享一个封装了PopupWindow实现弹出菜单的类,并说明它的实现与使用. 因对界面的需求,android原生的弹出菜单已不能满足我们的需求,自定义菜单成了我们的唯一选择,在 ...

  2. 如何利用PopupWindow实现弹出菜单并解决焦点获取以及与软键盘冲突问题

    如何利用PopupWindow实现弹出菜单并解决焦点获取以及与软键盘冲突问题 如何利用PopupWindow实现弹出菜单并解决焦点获取以及与软键盘冲突问题 在android中有时候可能要实现一个底部弹 ...

  3. 用PopupWindow实现弹出菜单(弹出的菜单采用自定义布局)

         用PopupWindow实现弹出菜单是一个比较好的方式.当然我们还有一个类PopupMenu也能实现弹出菜单,但那个太过于局限了,所以不是很推荐. 这个实例的效果是这样的:点击按钮后,一个菜 ...

  4. 【Android】创建Popwindow弹出菜单的两种方式

    方法一的Activity package com.app.test02; import android.app.Activity; import android.os.Bundle; import a ...

  5. 【Android】5.6 弹出菜单(PopUp Menus)

    分类:C#.Android.VS2015: 创建日期:2016-02-07 一.简介 功能描述:用户单击按钮弹出菜单.当用户选择一个菜单项,会触发MenuItemClick事件并让弹出的菜单消失:如果 ...

  6. Android于popWindow写弹出菜单

    1.什么是popWindow? popWindow这是对话的方式!文字解说android的方式来使用对话框,这就是所谓的popWindow. 2.popWindow特征 Android的对话框有两种: ...

  7. 【转】 教你如何创建类似QQ的android弹出菜单

    原文地址:http://www.apkbus.com/android-18034-1-1.html 大家可能看到android的自带的系统菜单比较难看,如图: 2011-12-4 23:13 上传 下 ...

  8. PopupWindow(2)简单示例-自定义弹出菜单

    本示例,用 popupWindow 自定义弹出菜单 public class CustomActionProvider extends ActionProvider implements OnMenu ...

  9. android中使用PopupWindow实现弹出窗口菜单

    结合上篇android中使用ViewPager实现图片拖动,我们实现了点击“帮助”按钮的功能,这一篇则是接着上一篇,让我们一起来完成“我的”按钮的功能,这一功能,则是使用PopupWindow来实现弹 ...

随机推荐

  1. js中一些常用的基本函数

    如何使用jquery刷新当前页面下面介绍全页面刷新方法:有时候可能会用到window.location.reload()刷新当前页面.parent.location.reload()刷新父亲对象(用于 ...

  2. eclipse 常用的一些设置

    1.行长度设置 http://blog.csdn.net/janronehoo/article/details/10047937 2.字体 windows -> preference -> ...

  3. 山寨QQ音乐的布局(一)

    学了两天IOS趁着还没忘光,巩固一下所学知识想做点东西,由于自己的设计能力有限,所以就山寨一下吧,说到山寨怎么能忘了腾讯呢,今天发现QQ音乐的设计风格是扁平化的,小清新风格,所以就山寨一下它吧.. 由 ...

  4. Ubuntu12.04 LTS Add Sources List

    1. First Step: sudo gedit /etc/apt/sources.list 2. Add Soures List Content: # deb cdrom:[Ubuntu LTS ...

  5. Windows消息拦截技术的应用(作者博客里有许多相关文章)

    民航合肥空管中心 周毅 一.前 言 众所周知,Windows程式的运行是依靠发生的事件来驱动.换句话说,程式不断等待一个消息的发生,然后对这个消息的类型进行判断,再做适当的处理.处理完此次消息后又回到 ...

  6. 关于” fatal error C1010: unexpected end of file while looking forprecompiled header directive”问题

    其中文意思是:致命错误C1010:意想不到的文件结束而寻找预编译头文件的指令错误执行cl exe. 经过多次的查找,终于解决这问题 方法一: 在头文件中加“#include "stdafx. ...

  7. 胜利大逃亡(续)(状态压缩bfs)

    胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  8. 将ImageView中的图片保存到本地相冊

    private void SaveImageToSysAlbum() { if (FileUtil.isSdCardExist()) { BitmapDrawable bmpDrawable = (B ...

  9. Codeforces #245(div2)

    A:A. Points and Segments (easy) 题目看了n久,開始认为尼玛这是div2的题目么,题目还标明了easy.. 意思是给你一n个点,m个区间,在n个点上放蓝球或者红球,然后让 ...

  10. 深入理解JVM : Java垃圾收集器

    如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现. Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商.不同版本的虚拟机所提供的垃圾收集器都可能会有很大差 ...