Android自定义上下文菜单

今天自定义了一个简单的Android菜单控件。实现方式是:PopupWindow和ListView。

现在来给大家分享一下源码:

SHContextMenu.java

核心代码部分:主要是对PopupWindow和ListView的初始化,为ListView设置数据源,以及封装了菜单的显示和隐藏的方法。还有提供了菜单的点击回调。

import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;

import com.eroad.ehr.R;
import com.eroad.product.bean.ContextMenuItem;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义上下文菜单
 * Created by MaJian on 16/4/28.
 */
public class SHContextMenu {

    private Context mContext;
    private List<ContextMenuItem> itemList;
    private PopupWindow popupWindow;
    private View contentView;
    private ListView mLvMenuList;
    private MenuAdapter menuAdapter;
    private OnItemSelectListener onItemSelectListener;

    public interface OnItemSelectListener{
        void onItemSelect(int position);
    }

    public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener){
        this.onItemSelectListener = onItemSelectListener;
    }

    public SHContextMenu(Context mContext){
        this.mContext = mContext;
        itemList = new ArrayList<>();
        initPopWindow();
    }

    /**
     * 初始化popwindow菜单
     */
    private void initPopWindow(){
        contentView = LayoutInflater.from(mContext).inflate(R.layout.popwindow_menu, null);
        popupWindow = new PopupWindow(contentView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        popupWindow.setFocusable(true);
        popupWindow.setOutsideTouchable(true);
        // 这个是为了点击“返回Back”也能使其消失,并且并不会影响你的背景
        popupWindow.setBackgroundDrawable(new BitmapDrawable());
        popupWindow.setAnimationStyle(R.style.PopupAnimation);
        mLvMenuList = (ListView) contentView.findViewById(R.id.lv_menu);
        menuAdapter = new MenuAdapter();
        mLvMenuList.setAdapter(menuAdapter);
        mLvMenuList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (onItemSelectListener != null){
                    onItemSelectListener.onItemSelect(position);
                }
                popupWindow.dismiss();
            }
        });
    }

    /**
     * 设置菜单列表数据源
     * @param itemList
     */
    public void setItemList(List<ContextMenuItem> itemList){
        this.itemList = itemList;
        menuAdapter.notifyDataSetChanged();
    }

    public void showMenu(View view){
        if (popupWindow == null)
            return;
        int[] location = new int[2];
        view.getLocationInWindow(location);
        // 状态栏的高度
        Rect frame = new Rect();
        ((Activity)mContext).getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        popupWindow.showAtLocation(((Activity)mContext).getWindow().getDecorView(), Gravity.TOP|Gravity.RIGHT, 0, ((Activity)mContext).getActionBar().getHeight()+frame.top-27);
    }

    /**
     * 上下文菜单列表适配器
     */
    class MenuAdapter extends BaseAdapter{

        /**
         * How many items are in the data set represented by this Adapter.
         *
         * @return Count of items.
         */
        @Override
        public int getCount() {
            return itemList == null ? 0 : itemList.size();
        }

        /**
         * Get the data item associated with the specified position in the data set.
         *
         * @param position Position of the item whose data we want within the adapter‘s
         *                 data set.
         * @return The data at the specified position.
         */
        @Override
        public Object getItem(int position) {
            return itemList.get(position);
        }

        /**
         * Get the row id associated with the specified position in the list.
         *
         * @param position The position of the item within the adapter‘s data set whose row id we want.
         * @return The id of the item at the specified position.
         */
        @Override
        public long getItemId(int position) {
            return position;
        }

        /**
         * Get a View that displays the data at the specified position in the data set. You can either
         * create a View manually or inflate it from an XML layout file. When the View is inflated, the
         * parent View (GridView, ListView...) will apply default layout parameters unless you use
         * {@link LayoutInflater#inflate(int, ViewGroup, boolean)}
         * to specify a root view and to prevent attachment to the root.
         *
         * @param position    The position of the item within the adapter‘s data set of the item whose view
         *                    we want.
         * @param convertView The old view to reuse, if possible. Note: You should check that this view
         *                    is non-null and of an appropriate type before using. If it is not possible to convert
         *                    this view to display the correct data, this method can create a new view.
         *                    Heterogeneous lists can specify their number of view types, so that this View is
         *                    always of the right type (see {@link #getViewTypeCount()} and
         *                    {@link #getItemViewType(int)}).
         * @param parent      The parent that this view will eventually be attached to
         * @return A View corresponding to the data at the specified position.
         */
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder = null;
            if (convertView == null){
                viewHolder = new ViewHolder();
                convertView = LayoutInflater.from(mContext).inflate(R.layout.popmenu_item, null);
                viewHolder.mIvIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
                viewHolder.mTvTitle = (TextView) convertView.findViewById(R.id.tv_title);
                viewHolder.mViewDivider = convertView.findViewById(R.id.view_divider);
                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }
            viewHolder.mTvTitle.setText(itemList.get(position).getTitle());
            viewHolder.mIvIcon.setImageDrawable(itemList.get(position).getImgDrawable());
//            convertView.setBackgroundColor(Color.parseColor(itemList.get(position).getColorString()));
            if (position == itemList.size() - 1){
                viewHolder.mViewDivider.setVisibility(View.INVISIBLE);
            } else {
                viewHolder.mViewDivider.setVisibility(View.VISIBLE);
            }

            return convertView;
        }

        class ViewHolder{
            TextView mTvTitle;
            ImageView mIvIcon;
            View mViewDivider;
        }
    }
}

popwindow_menu.xml

PopupWindow 的布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="match_parent">

    <ListView
        android:layout_width="180dp"
        android:layout_height="match_parent"
        android:id="@+id/lv_menu"
        android:divider="@null"
      android:background="@drawable/ic_bg_contextmenu">

    </ListView>
</LinearLayout>

PopupWindow展现样式

<style name="PopupAnimation" parent="android:Animation" mce_bogus="1">
        <item name="android:windowEnterAnimation">@anim/anim_popmenu_show</item>
        <item name="android:windowExitAnimation">@anim/anim_popmenu_hide</item>
    </style>

菜单隐藏的动画anim_popmenu_hide.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale android:fromXScale="1.0" android:toXScale="1.25"
        android:fromYScale="1.0" android:toYScale="1.25" android:pivotX="100%"
        android:pivotY="0%" android:duration="200" />
    <scale android:fromXScale="1.0" android:toXScale="0.48"
        android:fromYScale="1.0" android:toYScale="0.48" android:pivotX="100%"
        android:pivotY="0%" android:duration="400" android:delay="200" />
    <alpha android:interpolator="@android:anim/linear_interpolator"
        android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="400" />
</set>

菜单显示的动画anim_popmenu_show.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale android:fromXScale="0.6" android:toXScale="1.1"
        android:fromYScale="0.6" android:toYScale="1.1" android:pivotX="100%"
        android:pivotY="0%" android:duration="200" />
    <scale android:fromXScale="1.0" android:toXScale="0.91"
        android:fromYScale="1.0" android:toYScale="0.91" android:pivotX="100%"
        android:pivotY="0%" android:duration="400" android:delay="200" />
    <alpha android:interpolator="@android:anim/linear_interpolator"
        android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="400" />
</set>

上下文菜单Item的Bean

package com.eroad.product.bean;

import android.graphics.drawable.Drawable;

/**
 * 上下文菜单项对象
 * Created by MaJian on 16/4/28.
 */
public class ContextMenuItem {

    private Drawable imgDrawable;
    private String title;
    private boolean visible;
    private String colorString;

    public ContextMenuItem(Drawable imgDrawable, String title, boolean visible, String colorString) {
        this.imgDrawable = imgDrawable;
        this.title = title;
        this.visible = visible;
        this.colorString = colorString;
    }

    public String getColorString() {
        return colorString;
    }

    public void setColorString(String colorString) {
        this.colorString = colorString;
    }

    public boolean isVisible() {
        return visible;
    }

    public void setVisible(boolean visible) {
        this.visible = visible;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Drawable getImgDrawable() {
        return imgDrawable;
    }

    public void setImgDrawable(Drawable imgDrawable) {
        this.imgDrawable = imgDrawable;
    }

}

现在和大家说一下菜单的调用方式

SHContextMenu shContextMenu = new SHContextMenu(getActivity());
                List<ContextMenuItem> itemList = new ArrayList<>();
                itemList.add(new ContextMenuItem(getResources().getDrawable(R.drawable.ic_create_company), "草稿", true, "#FFFFFF"));
                itemList.add(new ContextMenuItem(getResources().getDrawable(R.drawable.ic_create_company), "草稿", true, "#FFFFFF"));
                itemList.add(new ContextMenuItem(getResources().getDrawable(R.drawable.ic_create_company), "草稿", true, "#FFFFFF"));
                itemList.add(new ContextMenuItem(getResources().getDrawable(R.drawable.ic_create_company), "草稿", true, "#FFFFFF"));
                itemList.add(new ContextMenuItem(getResources().getDrawable(R.drawable.ic_create_company), "草稿", true, "#FFFFFF"));
                shContextMenu.setItemList(itemList);
                shContextMenu.setOnItemSelectListener(new SHContextMenu.OnItemSelectListener() {
                    @Override
                    public void onItemSelect(int position) {
                        SHToast.showToast(getActivity(), position + "");
                    }
                });
                shContextMenu.showMenu(et_search);

当然最后是大家最关心的效果图:

时间: 2024-08-15 05:17:21

Android自定义上下文菜单的相关文章

【jQuery】smartMenu右键自定义上下文菜单插件(似web QQ)

一.这是什么样的一个插件 浏览器默认的右键选项有时候并不是我们所需要的,我们希望浏览器的右键选项菜单更智能,可以灵活自定义.比较有代表性的就是web QQ,例如下面截图: QQ邮箱中也是有此功能. 显然这种东西貌似还是蛮强大与实用的,于是我就抽空写了个可以右键自定义上下文菜单的jQuery插件 – smartMenu,直接一行代码绑定,就可以让我们轻松实现页面元素的自定义上下文功能.至于具体如何实用与绑定,就是本文的的主要内容,也即是下文即 将介绍的内容. 二.插件效果.大小.使用等简介 效果首

android,关于上下文菜单ContextMenu数据值的转递

在长按某view时,如该view有绑定OnCreateContextMenuListener,则会弹出ContextMenu上下文菜单,这类似于右键菜单,菜单弹出后点击某菜单项,则Activity或Fragment中的 public boolean onContextItemSelected(MenuItem item) 方法会响应菜单的点击,根据item的id来确定点击的是哪一个菜单项,从而进行进一步的操作. 那么现在的问题是,有时候我们只知道了点击的哪个菜单项是不够的,还需要知道更多的信息,

android ContextMenu上下文菜单

本例子对textview添加了一个上下文菜单,长按textview会显示菜单 public class MainActivity extends Activity { private TextView edit; final int MENU1 = 0x111; final int MENU2 = 0x112; final int MENU3 = 0x113; @Override protected void onCreate(Bundle savedInstanceState) { super

Mint linux 自定义上下文菜单实现ZIP压缩文件无乱码解压

1. 前提条件 我的Mint Linux 是Thunar文件管理器(默认的). 2. 配置自定义动作 打开Thunar文件管理器,点击菜单“编辑”=>“配置自定义动作”.点击“+”添加一个新的.输入下图的内容: 配置出现条件: 3. 最终效果

jQuery smartMenu右键自定义上下文菜单插件

http://www.zhangxinxu.com/wordpress/?p=1667 1 <%@ page contentType="text/html; charset=UTF-8"%> 2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 3 <html&g

android项目--上下文菜单

在XHTML里,标签必须是开头和结尾成对出现,双标签: 例: <html></html> 文字换行: 直接输入文字 <p> 我是一个好学生 我是一个好学生 我是一个好学生 </p> 它就会显示,我是一个好学生我是一个好学生我是一个好学生 并不会显示你写时的作用,这时要换行你有两个做法 1.在每局后面加一个<br> 2.直接用<pre> 标签嵌套: 1.给字体改颜色 例: <body text="你要的颜色英文单词&qu

自定义上下文菜单,contextmenu事件

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="myDiv">dsdafsdfasdfas dsfsfasdf asd fas dfa sdfa sdf asdf asd f

安卓开发复习笔记——Menu菜单组件(选项菜单,上下文菜单,子菜单)

菜单是用户界面中最常见的元素之一,使用非常频繁,在Android中,菜单被分为如下三种,选项菜单(OptionsMenu).上下文菜单(ContextMenu)和子菜单(SubMenu). 菜单的实现方式有2种:一种是通过布局文件xml生成菜单,另一种是通过代码生成. 三种菜单内容有点多,不过大体相似,一次性讲完吧,本人偏好代码动态生成,下面就以代码为例. 1.选项菜单(OptionsMenu) 先来看下选项菜单的效果图:   在一个Activity界面中点击手机Menu键,在屏幕下方弹出的菜单

Android学习(二十二)ContentMenu上下文菜单

一.上下问菜单 在某个菜单项上长按,会弹出一个菜单,这个就是上下文菜单.有点类似与Windows系统中的右键菜单. 二.上下文菜单的内容 1.标题 2.图标 3.菜单项 4.对应的菜单事件 三.OptionsMenu和ContentMenu的区别: 1.OptionMenu对应的Activity,一个Activity只能拥有一个选项菜单. 2. ContentMenu对应的View,每个View都可以设置上下文菜单. 3.一般情况下,上下文菜单常用于ListView或者GirdView. 四.如