在本文当中,我将会与大家分享一个封装了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. javascript模拟html title

    这只是个学习原生javascript过程中的一个练手效果 不做说明解释 直接上代码 算是个参考 <!doctype html> <html> <head> < ...

  2. 从苹果的appstore谈谈web前端那丝毫的追求

    献上链接:点击进入itunes打开页面,我们先找到App 的logo图比如这个图很简单的一个图标,估计多数人选择的是上传一张处理好圆角,border的图片作为app logo,但问题是苹果觉得,你们每 ...

  3. 1分钟快速生成用于网页内容提取的xslt

      1,项目背景   在<Python即时网络爬虫项目说明>一文我们说过要做一个通用的网络爬虫,而且能节省程序员大半的时间,而焦点问题就是提取器使用的抓取规则需要快速生成.在python使 ...

  4. App_Code

    App_Code,文件夹是·NET平台下.在创建网站时,系统为类自动放的位置.它位于Web应用程序根目录下,其存储所有应当作为应用程序的一部分动态编译的类文件.这些类文件自 动链接到应用程序,而不需要 ...

  5. WPF GroupBox 样式分享

    原文:WPF GroupBox 样式分享 默认样式 GroupBox 样式分享" title="WPF GroupBox 样式分享"> 添加样式后 GroupBox ...

  6. perl 实现微信简版<2>

    <pre name="code" class="python">use LWP::UserAgent; use URI::Escape; use N ...

  7. __declspec(dllimport)的作用

    是时候总结一下__declspec(dllimport)的作用了.可能有人会问:__declspec(dllimport)和__declspec(dllexport)是一对的,在动态链接库中__dec ...

  8. 滚动栏范围位置函数(SetScrollRange、SetScrollPos、GetScrollRange、GetScrollPos)

    滚动栏的范围是一对整数,默认情况下,滚动栏的范围是0~100. SetScrollRange(hwnd,iBar,iMin,iMax,bRedraw)这里的iBar參数要么是SB_VERT,要么是SB ...

  9. poj 2186 (强连通缩点)

    题意:有N只奶牛,奶牛有自己认为最受欢迎的奶牛.奶牛们的这种“认为”是单向可传递的,当A认为B最受欢迎(B不一定认为A最受欢迎),且B认为C最受欢迎时,A一定也认为C最受欢迎.现在给出M对这样的“认为 ...

  10. 【最大流,二分图匹配】【hdu2063】【过山车】

    题意:裸的求二分图匹配 建立一个源点 连向一边所有的点 容量为1; 另外一边点都连向汇点  容量为1; 二分图的边容量也为1 源点汇点求一遍最大流即可 #include <cstdio> ...