工程中需要做一个较负责并比较美观的menu菜单,使用Android自带的menu是达不到设计要求的效果的,经过上网搜索,决定使用PopupWindow来实现自定义menu。
PopupWindow在android.widget包下,弹出窗口的形式展示。官方文档对该控件的描述是:“一个弹出窗口控件,可以用来显示任意视图(View),而且会浮动在当前 活动(activity)的顶部”。PopupWindow可以让我们实现多种自定义控件,例如:menu、alertdialog等弹窗似的View。
使用PopupWindow来做自定义menu,往PopupWindow增加一个子View,子View的布局就是menu的布局。
出现和退出的动画:可以给PopUpWindow或它的子view添加。
下面边贴代码边讲解具体实现
自定义menu类文件:该文件定义了menu的布局,popupwindow的属性,及控件响应事件。
public class BottomMenu extends PopupWindow {
private Context context;
private View bottom_menu;
private ImageButton menuButton1,menuButton2,menuButton3,menuButton4,menuButton9,menuButton0;
private View parent;
public BottomMenu(Context _context,View _parent,Activity activity) {
super(_context);
this.context = _context;
this.parent = _parent;
LayoutInflater mInflate = LayoutInflater.from(context);
bottom_menu = mInflate.inflate(R.layout.menu_layout, null);
bottom_menu.setFocusableInTouchMode(true);
bottom_menu.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if ((keyCode == KeyEvent.KEYCODE_MENU)&&(isShowing())) {
dismiss();
}else if((keyCode == KeyEvent.KEYCODE_BACK)&&(isShowing())) {
dismiss();
}
return false;
}
});
setContentView(bottom_menu);
setWidth(LayoutParams.FILL_PARENT);
setHeight(LayoutParams.WRAP_CONTENT);
setBackgroundDrawable(null);
setFocusable(true);
setAnimationStyle(R.style.PopupAnimation);
menuButton1=(ImageButton) bottom_menu.findViewById(R.id.menuButton1);
menuButton2=(ImageButton) bottom_menu.findViewById(R.id.menuButton2);
menuButton3=(ImageButton) bottom_menu.findViewById(R.id.menuButton3);
menuButton4=(ImageButton) bottom_menu.findViewById(R.id.menuButton4);
menuButton9=(ImageButton) bottom_menu.findViewById(R.id.menuButton9);
menuButton0=(ImageButton) bottom_menu.findViewById(R.id.menuButton0);
MyListener mListener=new MyListener(context,activity);
menuButton1.setOnClickListener(mListener);
menuButton2.setOnClickListener(mListener);
menuButton3.setOnClickListener(mListener);
menuButton4.setOnClickListener(mListener);
menuButton9.setOnClickListener(mListener);
menuButton0.setOnClickListener(mListener);
update();
}
public void setMenuEvent() {
if ((this != null) && (!this.isShowing())) {
Log.i("menu", "menu show");
this.showAtLocation(parent, Gravity.BOTTOM, 0, 0);
}
}
public void finishMenuEvent(){
if ((this != null)&&(this.isShowing())) {
dismiss();
}
}
}
可以看到,在构造函数里,对布局和一些属性都进行了设置,下面的setMenuEvent()函数实现menu显示,finishMenuEvent()函数实现menu消失。
注意:
bottom_menu.setOnKeyListener(new OnKeyListener() 这个函数实现了对menu键和return键的响应,必须添加,同时
bottom_menu.setFocusableInTouchMode(true)也必须有,不然不会响应。
这里为了响应menu中的点击事件我在menu的类中重写了一个listener。
class MyListener implements OnClickListener{
private Context context;
private Activity activity;
public MyListener(Context _context,Activity _activity){
super();
this.context=_context;
this.activity=_activity;
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
int layoutId = v.getId();
Intent intent = new Intent();
switch (layoutId) {
case R.id.menuButton1:
Log.i("menu", "menu botton 1");
Toast.makeText(context, "add menu 1", Toast.LENGTH_SHORT).show();
break;
case R.id.menuButton2:
Log.i("menu", "menu botton 2");
Toast.makeText(context, "add menu 2", Toast.LENGTH_SHORT).show();
break;
case R.id.menuButton3:
Log.i("menu", "menu botton 3");
Toast.makeText(context, "add menu 3", Toast.LENGTH_SHORT).show();
break;
case R.id.menuButton4:
Log.i("menu", "menu botton 4");
Toast.makeText(context, "add menu 4", Toast.LENGTH_SHORT).show();
break;
case R.id.menuButton9:
Log.i("menu", "menu botton setting");
Toast.makeText(context, "add menu setting", Toast.LENGTH_SHORT).show();
break;
case R.id.menuButton0:
Log.i("menu", "menu botton exit");
activity.finish();
break;
}
}
}
接下来在要实现menu的Activity里面加入如下几段代码
bottomMenu=new BottomMenu(getBaseContext(), findViewById(R.id.linearLayout), this);
这段代码是创建menu,其中三个参数分别是context,父layout,Activity。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add("menu");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
bottomMenu.setMenuEvent();
return false;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// TODO Auto-generated method stub
Log.v("Tinker", "test");
return super.dispatchKeyEvent(event);
}
可以看出以上代码其实是Android原生menu的实现形式,其实是进行了拦截,这里必须有一个 menu.add() 。
protected void onStop() {
super.onStop();
bottomMenu.finishMenuEvent();
}
以上,控制Activity进入休眠时使menu消失,这个函数是为了以防万一,并不一定是必要的。
XML布局的代码这里不再详述,下面的demo里有。
这里简要介绍下弹出和消失的动画效果。
第一段代码中有一行是设置动画效果的。
setAnimationStyle(R.style.PopupAnimation);
在style中:
<style name="PopupAnimation" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/menu_in</item>
<item name="android:windowExitAnimation">@anim/menu_out</item>
</style>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="100%p" android:toYDelta="0" android:duration="200" />
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="500" />
</set>
第一行设置弹出的快慢
第二项设置淡入淡出的快慢
demo下载:BottomMenuDemo