在本文当中,我将会与大家分享一个封装了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. mac10.9 设置vim tab

    vimrc系统文件目录 /usr/share/vim 在vimrc中添加以下代码后,重启vim即可实现按TAB产生4个空格:set ts=4  (注:ts是tabstop的缩写,设TAB宽4个空格)s ...

  2. KNN(k-nearest neighbor的缩写)又叫最近邻算法

    KNN(k-nearest neighbor的缩写)又叫最近邻算法 机器学习笔记--KNN算法1 前言 Hello ,everyone. 我是小花.大四毕业,留在学校有点事情,就在这里和大家吹吹我们的 ...

  3. MYSQL create database 和 create table 做了一些什么!

    create database Studio; 这样就可以创建一个数据库了.他包涵一些什么呢? 可以看到它创建了一个文件夹,下面我们进去看一下它里面有一些什么东西. 还是先建一张表再进去吧,运行一下这 ...

  4. hdu1258Sum It Up (DFS)

    Description Given a specified total t and a list of n integers, find all distinct sums using numbers ...

  5. Linux内核中常见内存分配函数(三)

    ioremap void * ioremap (unsigned long offset, unsigned long size) ioremap是一种更直接的内存“分配”方式,使用时直接指定物理起始 ...

  6. 网易云课堂_C++开发入门到精通_章节2:引用和函数的高级用法

    课时6函数重载 函数重载 在C语言头文件中的extern "C" //常见的C语言头文件格式 #ifndef _FUNC_ #define _FUNC_ #ifdef __cplu ...

  7. 网页前台的iframe控制内部刷新子页

    <body> <!--Header--> <uc1:top runat="server" ID="top" /> <! ...

  8. python内置函数(2)-递归与迭代

    这篇文章简单介绍了迭代和递归的概念.两者的区别 什么是迭代: 迭代是重复反馈过程的活动,其目的通常是为了接近并达到所需的目标或结果.每一次对过程的重复被称为一次“迭代”,而每一次迭代得到的结果会被用来 ...

  9. Android UI目录

    Android UI目录 序:最近一直想进阶android应用开发,虽然对一些相关的android知识都大体熟悉,但是自己的android知识体系,经不起推敲.经不起高手的垂问.经过几个月的努力学习, ...

  10. 【简单项目框架一】Fragment实现的底部导航

    流行的应用的导航一般分为两种,一种是底部导航,一种是侧边栏. 我所做的项目涉及到比较多的是底部导航,今天我就把项目中使用的一种实现方式分享一下. 主要实现思路是:在一个Activity里面底部添加四个 ...