Android自定义上下文菜单
16lz
2021-01-26
今天自定义了一个简单的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);
当然最后是大家最关心的效果图:
更多相关文章
- Android(安卓)- 菜单
- Android提高十七篇之多级树形菜单的实现[转]
- android中menu.add()的使用说明
- Android(安卓)Contextual ActionBar (CAB)上下文操作栏使用指南
- [置顶] Android:实现仿 美团/淘宝 多级分类菜单效果
- 仿qq横向滑动删除的 SwipeMenuListView
- 【Android】菜单功能的实现:弹出Popup菜单 以及小结
- 如何用eclipse编译调试adnroid的Browser
- Android(安卓)M 新控件 TabLayout 与 NavigationView 实践