Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發技巧——使用PopupWindow實現彈出菜單

Android開發技巧——使用PopupWindow實現彈出菜單

編輯:關於Android編程

在本文當中,我將會與大家分享一個封裝了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 ([email protected])
 * Time: 14-6-13 下午1:51
 */
public abstract class PopMenu {
    /**
     * 上下文.
     */
    private Context mContext;
    /**
     * 菜單項
     */
    private ArrayList mItemList;
    /**
     * 列表適配器.
     */
    private ArrayAdapter mAdapter;
    /**
     * 菜單選擇監聽.
     */
    private OnItemSelectedListener mListener;
    /**
     * 列表.
     */
    private ListView mListView;
    /**
     * 彈出窗口.
     */
    private PopupWindow mPopupWindow;

    public PopMenu(Context context) {
        mContext = context;
        mItemList = new ArrayList(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 onCreateAdapter(Context context, ArrayList 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 ([email protected])
 * 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 onCreateAdapter(Context context, ArrayList items) {
        return new ArrayAdapter(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 ([email protected])
 * 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);
    }
}

彈出菜單的布局文件如下:



    

    

其中的ImageView的照片是一個黑色三角圖案。這個等在最後我發一下效果圖就明白了。ListView背景是一張黑色圖片。

接下來是item的布局,只是一個TextView,代碼如下:




使用代碼如下:
    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的下拉菜單顯示了。效果如下:


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved