一、OptionMenu的使用
1、代码生成menu(重写activity的onCreateOptionMenu()方法)
@Override public boolean onCreateOptionsMenu(Menu menu) { this.menu = menu; int groupId = 1; MenuItem item1 = menu.add(groupId, Menu.FIRST + 1, 1, "将第二组item不可见"); item1.setIcon(R.mipmap.ic_launcher); menu.add(groupId, Menu.FIRST + 2, 2, "将第二组item可见"); menu.add(groupId, Menu.FIRST + 3, 3, "将第二组item不可用"); MenuItem item4 = menu.add(groupId, Menu.FIRST + 4, 4, "将第二组item可用"); item4.setIcon(R.mipmap.ic_launcher); menu.add(groupId, Menu.FIRST + 5, 5, "将第二组item可单选"); menu.add(groupId, Menu.FIRST + 6, 6, "将第二组item可多选"); groupId = 2; MenuItem item7 = menu.add(groupId, Menu.FIRST + 7, 7, "menu2_1"); item7.setIcon(R.mipmap.ic_launcher); MenuItem item8 = menu.add(groupId, Menu.FIRST + 8, 8, "menu2_2"); item8.setIcon(R.mipmap.ic_launcher); SubMenu subMenu = menu.addSubMenu(groupId, Menu.FIRST + 9, 9, "sub menu"); subMenu.add(groupId, Menu.FIRST + 10, 1, "sub1"); subMenu.add(groupId, Menu.FIRST + 11, 2, "sub2"); /** * 这个监听事件可以对item的点击事件进行拦截,拦截后的item在onOptionsItemSelected()中不会得到执行 */ item1.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { return true;//返回true为拦截,false不拦截 } }); return true; }使用menu.add(int groupId, int itemId, int order, charsequence title);
groupId: 可以对MenuItem进行分组,以便可以再代码中对某一组MenuItem进行操作,如menu.setGroupXXX();
itemId: MenuItem的id,可以使用menuItem.getItemId(int id)获取到,便于对MenuItem的点击事件处理
order: 根据这个对menuItem的排序,越小排在越前面,如果某两个item的order相同,则按照代码添加顺序排列
title: 该menuitem的内容
/
menu.addSubMenu(int groupId, int itemId, int order, charsequence title);//使用同上
menuitem.setOnMenuItemClickListener()//可以直接在这里设置menuitem的点击事件,可以对onOptionsItemSeleted()进行拦截
onCreateOptionMenu()return true表示展示菜单,return false表示隐藏菜单
2、添加menuitem的点击事件,在activity的onOptionsItemSeleted(MenuItem menuitem)中进行设置
@Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { case Menu.FIRST + 1: menu.setGroupVisible(2, false); break; case Menu.FIRST + 2: menu.setGroupVisible(2, true); break; case Menu.FIRST + 3: menu.setGroupEnabled(2, false); break; case Menu.FIRST + 4: menu.setGroupEnabled(2, true); break; case Menu.FIRST + 5: menu.setGroupCheckable(2, true, true); break; case Menu.FIRST + 6: menu.setGroupCheckable(2, true, false); break; case Menu.FIRST + 7: Toast.makeText(this, "menu2_1", Toast.LENGTH_SHORT).show(); break; case Menu.FIRST + 8: Toast.makeText(this, "menu2_2", Toast.LENGTH_SHORT).show(); break; case Menu.FIRST + 10: Toast.makeText(this, "sub1", Toast.LENGTH_SHORT).show(); break; case Menu.FIRST + 11: Toast.makeText(this, "sub2", Toast.LENGTH_SHORT).show(); break; }
3、xml生成menu
在res目录下新建menu目录,在这下面创建menu资源文件如mani_menu.xml
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <group android:id="@+id/group1" android:checkableBehavior="all"> <item android:id="@+id/group1_item1" android:icon="@mipmap/ic_launcher" android:title="item1" app:showAsAction="always"></item> <item android:id="@+id/group1_item2" android:icon="@mipmap/ic_launcher" android:title="item2" app:showAsAction="always"></item> <item android:id="@+id/group1_item3" android:icon="@mipmap/ic_launcher" android:title="item3" app:showAsAction="always"></item> <item android:id="@+id/group1_item4" android:icon="@mipmap/ic_launcher" android:title="item4" app:showAsAction="always"></item> <item android:id="@+id/group1_item5" android:icon="@mipmap/ic_launcher" android:title="item5" app:showAsAction="always"></item> <item android:id="@+id/group1_item6" android:title="点我" app:showAsAction="always"> <menu> <item android:id="@+id/sub_item1" android:icon="@mipmap/ic_launcher" android:title="sub item1"></item> <item android:id="@+id/sub_item2" android:icon="@mipmap/ic_launcher" android:title="sub item2"></item> <item android:id="@+id/sub_item3" android:icon="@mipmap/ic_launcher" android:title="sub item3"></item> </menu> </item> <item android:id="@+id/group1_item7" android:icon="@mipmap/ic_launcher" android:title="item7" ></item> </group> </menu>
注意xml中showAsAction的用法,根据编译版本的不同,使用不同,23使用的app:showAsAction ,该属性可以设置menuitem是展示在actionbar上还是现实在overflow中
其中设置在actionbar上的menuitem只要设置了icon都会显示,但是在overflow中的menuitem的icon就分系统版本不同,而有不同,android 4.0之前会显示icon,android4.0之后显示不出icon,解决方法如下:
/** * 利用反射机制调用MenuBuilder中的setOptionIconsVisable(), * 如果是集成自AppCompatActivity则不行,需要在onPreareOptionPanel()中调用该方法 * @param menu 该menu实质为MenuBuilder,该类实现了Menu接口 * @param enable enable为true时,菜单添加图标有效,enable为false时无效。因为4.0系统之后默认无效 */ private void setIconEnable(Menu menu, boolean enable) { if (menu != null) { try { Class clazz = menu.getClass(); if (clazz.getSimpleName().equals("MenuBuilder")) { Method m = clazz.getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE); m.setAccessible(true); //MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征) m.invoke(menu, enable); } } catch (Exception e) { e.printStackTrace(); } } }activity中传进来的menu其实是一个MenuBuilder的实例,而在MenuBuilder中有一个方法setOptionIconVisable(),这里只是用的向上转型,所以这里的menu调用不到,
而该方法又是一个访问修饰符为默认缺省的,所以只能利用反射机制
那么该在哪里调用该方法呢,这里为了兼容AppCompatActivity,我们在onPrepareOptionPanel()中调用
/** * android 4.0以后使用AppCompatActivity必须在该方法中调用setIconEnable(), * 隐藏的menuitem的icon才会显示 * android 4.0以后其他的activity可以再onPrepreOptionMenu()中调用 * android 4.0以前可以正常显示overflow中的menuitem的icon * @param view * @param menu * @return */ @Override protected boolean onPrepareOptionsPanel(View view, Menu menu) { setIconEnable(menu, true);//让在overflow中的menuitem的icon显示 return super.onPrepareOptionsPanel(view, menu); }
运行之后可以看到如下图:
有的手机有menu实体键,这个时候actionbar上将不会显示右上角的竖直的三个小点,而是按实体menu键显示menuitem,这不方便我们做统一的界面管理,这个时候可以再activity的onCreate()函数中调用以下代码
/** * 通过反射,设置实体menu键可用与否 * 该方法在onCreate()中调用 * @param enable false:实体键不可用,会在actionbar上显示小点 * true:可用,点击menu实体键才会显示menuitem */ public void setHasPermanentMenuKey(boolean enable){ try { ViewConfiguration mconfig = ViewConfiguration.get(this); Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey"); if(menuKeyField != null) { menuKeyField.setAccessible(true); menuKeyField.setBoolean(mconfig, enable); } } catch (Exception ex) { } }
有的时候系统默认的title也就是actionbar并不能达到我们的预期,这时候我们一般采用自定义的方法,然后把系统默认的隐藏掉,而使用自己的,其实不必如此,android本身支持自定义actionBar的,只需要在activity的oncreate()函数中获取到actionbar,然后设置自己的actionbar布局就可以了如下:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_drawer_layout); ButterKnife.bind(this); setHasPermanentMenuKey(false); /* * ActionBar */ ActionBar actionBar = getSupportActionBar(); //设置自定义actionbar的view actionBar.setCustomView(R.layout.action_bar_layout); //设置展示的options为DISPLAY_SHOW_CUSTOM actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); //设置showCustom为true actionBar.setDisplayShowCustomEnabled(true); //实例化自定义actionbar的view actionImageView = (ImageView) actionBar.getCustomView().findViewById(R.id.image_view); actionTextView = (TextView) actionBar.getCustomView().findViewById(R.id.textview); actionPersonalView = (TextView) actionBar.getCustomView().findViewById(R.id.personal_textview); actionPersonalView.setOnClickListener(this); actionImageView.setOnClickListener(this);
这里注意使用getSupportActionBar()的时候有些时候获取到的actionbar为null,这个时候检查是否在menifest或者代码中设置了No_title或者全屏,设置成任何一个都会导致null
这里的actionBar.setCustomView(int layout);这个就可以设置自定义actionbar布局
我的布局acdtion_bar_layout如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/image_view" android:layout_width="40dp" android:layout_height="40dp" android:layout_gravity="center_vertical" android:src="@mipmap/ic_launcher"/> <TextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:textSize="20sp" android:text="标题" /> <TextView android:id="@+id/personal_textview" android:layout_width="match_parent" android:layout_height="match_parent" android:text="个人中心" android:gravity="right|center_vertical" android:layout_gravity="right"/> </LinearLayout>得到的action如下:
二、侧滑菜单Drawerlayout
该类位于
android.support.v4.widget.DrawerLayout
使用很简单,直接在xml中使用按照规则使用即可
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.user.customviewdemo.drawerlayout.DrawerLayoutActivity"> <!--主界面布局 主界面写在最上面--> <LinearLayout android:id="@+id/content_frame" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textview" android:layout_marginTop="100dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="滑出左菜单" android:textSize="30sp" android:gravity="center"/> <TextView android:id="@+id/textview1" android:layout_marginTop="100dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="30sp" android:text="滑出右菜单" android:gravity="center"/> <ImageView android:id="@+id/image_view" android:layout_marginTop="50dp" android:layout_width="50dp" android:layout_height="50dp" android:src="@mipmap/ic_launcher" android:scaleType="center" android:layout_gravity="center_horizontal"/> </LinearLayout> <!--左侧滑菜单布局 layout_gravity="start" --> <ListView android:id="@+id/left_drawer" android:layout_width="200dp" android:layout_height="match_parent" android:layout_gravity="start" android:background="@android:color/holo_green_dark" android:choiceMode="singleChoice" android:divider="@android:color/transparent" android:dividerHeight="0dp" /> <!--右侧滑菜单布局 layout_gravity="end"--> <RelativeLayout android:id="@+id/right_drawer" android:layout_width="220dp" android:layout_height="match_parent" android:layout_gravity="end" android:background="#111" android:gravity="center_horizontal" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:text="个人中心" android:textColor="@android:color/white" android:textSize="24sp" /> </RelativeLayout> </android.support.v4.widget.DrawerLayout>
activity中代码如下:
package com.example.user.customviewdemo.drawerlayout; import android.os.Bundle; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; import android.view.ViewConfiguration; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.example.user.customviewdemo.R; import java.lang.reflect.Field; import java.lang.reflect.Method; import butterknife.Bind; import butterknife.ButterKnife; public class DrawerLayoutActivity extends AppCompatActivity implements View.OnClickListener { @Bind(R.id.left_drawer) ListView leftDrawer; @Bind(R.id.right_drawer) RelativeLayout rightDrawer; @Bind(R.id.drawer_layout) DrawerLayout drawerLayout; @Bind(R.id.textview) TextView textview; @Bind(R.id.textview1) TextView textview1; @Bind(R.id.image_view) ImageView imageView; private ImageView actionImageView; private TextView actionTextView; private TextView actionPersonalView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_drawer_layout); ButterKnife.bind(this); setHasPermanentMenuKey(false); /* * ActionBar */ ActionBar actionBar = getSupportActionBar(); //设置自定义actionbar的view actionBar.setCustomView(R.layout.action_bar_layout); //设置展示的options为DISPLAY_SHOW_CUSTOM actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); //设置showCustom为true actionBar.setDisplayShowCustomEnabled(true); //实例化自定义actionbar的view actionImageView = (ImageView) actionBar.getCustomView().findViewById(R.id.image_view); actionTextView = (TextView) actionBar.getCustomView().findViewById(R.id.textview); actionPersonalView = (TextView) actionBar.getCustomView().findViewById(R.id.personal_textview); actionPersonalView.setOnClickListener(this); actionImageView.setOnClickListener(this); /** * 左边侧滑菜单 */ String[] strs = getResources().getStringArray(R.array.menu_list); leftDrawer.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strs)); /** * 主界面按钮添加监听,点击滑出菜单 */ textview.setOnClickListener(this); textview1.setOnClickListener(this); /** * drawerLayout添加监听,监听侧滑过程,包括打开,关闭,和侧滑offSet * ActionBarDrawerToggle继承了DrawerLayout.DrawerListener * 所以可以直接使用 */ drawerLayout.addDrawerListener(new ActionBarDrawerToggle(this, drawerLayout, R.string.hello_blank_fragment, R.string.app_name) { @Override public void onDrawerOpened(View drawerView) { super.onDrawerOpened(drawerView); } @Override public void onDrawerClosed(View drawerView) { super.onDrawerClosed(drawerView); actionTextView.setText("标题"); } @Override public void onDrawerSlide(View drawerView, float slideOffset) { super.onDrawerSlide(drawerView, slideOffset); //设置actionbar中的icon和主界面的imageview旋转 actionImageView.setRotation(slideOffset*90); imageView.setRotation(slideOffset*270); } }); } /** * 通过反射,设置实体menu键可用与否 * 该方法在onCreate()中调用 * @param enable false:实体键不可用,会在actionbar上显示小点 * true:可用,点击menu实体键才会显示menuitem */ public void setHasPermanentMenuKey(boolean enable){ try { ViewConfiguration mconfig = ViewConfiguration.get(this); Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey"); if(menuKeyField != null) { menuKeyField.setAccessible(true); menuKeyField.setBoolean(mconfig, enable); } } catch (Exception ex) { } } /** * android 4.0以后使用AppCompatActivity必须在该方法中调用setIconEnable(), * 隐藏的menuitem的icon才会显示 * android 4.0以后其他的activity可以再onPrepreOptionMenu()中调用 * android 4.0以前可以正常显示overflow中的menuitem的icon * @param view * @param menu * @return */ @Override protected boolean onPrepareOptionsPanel(View view, Menu menu) { setIconEnable(menu, true);//让在overflow中的menuitem的icon显示 return super.onPrepareOptionsPanel(view, menu); } private Menu menu; @Override public boolean onCreateOptionsMenu(Menu menu) { this.menu = menu; int groupId = 1; MenuItem item1 = menu.add(groupId, Menu.FIRST + 1, 1, "将第二组item不可见"); item1.setIcon(R.mipmap.ic_launcher); menu.add(groupId, Menu.FIRST + 2, 2, "将第二组item可见"); menu.add(groupId, Menu.FIRST + 3, 3, "将第二组item不可用"); MenuItem item4 = menu.add(groupId, Menu.FIRST + 4, 4, "将第二组item可用"); item4.setIcon(R.mipmap.ic_launcher); menu.add(groupId, Menu.FIRST + 5, 5, "将第二组item可单选"); menu.add(groupId, Menu.FIRST + 6, 6, "将第二组item可多选"); groupId = 2; MenuItem item7 = menu.add(groupId, Menu.FIRST + 7, 7, "menu2_1"); item7.setIcon(R.mipmap.ic_launcher); MenuItem item8 = menu.add(groupId, Menu.FIRST + 8, 8, "menu2_2"); item8.setIcon(R.mipmap.ic_launcher); SubMenu subMenu = menu.addSubMenu(groupId, Menu.FIRST + 9, 9, "sub menu"); subMenu.add(groupId, Menu.FIRST + 10, 1, "sub1"); subMenu.add(groupId, Menu.FIRST + 11, 2, "sub2"); /** * 这个监听事件可以对item的点击事件进行拦截,拦截后的item在onOptionsItemSelected()中不会得到执行 */ item1.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { return true;//返回true为拦截,false不拦截 } }); return true; } /** * 利用反射机制调用MenuBuilder中的setOptionIconsVisable(), * 如果是集成自AppCompatActivity则不行,需要在onPreareOptionPanel()中调用该方法 * @param menu 该menu实质为MenuBuilder,该类实现了Menu接口 * @param enable enable为true时,菜单添加图标有效,enable为false时无效。因为4.0系统之后默认无效 */ private void setIconEnable(Menu menu, boolean enable) { if (menu != null) { try { Class clazz = menu.getClass(); if (clazz.getSimpleName().equals("MenuBuilder")) { Method m = clazz.getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE); m.setAccessible(true); //MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征) m.invoke(menu, enable); } } catch (Exception e) { e.printStackTrace(); } } } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { case Menu.FIRST + 1: menu.setGroupVisible(2, false); break; case Menu.FIRST + 2: menu.setGroupVisible(2, true); break; case Menu.FIRST + 3: menu.setGroupEnabled(2, false); break; case Menu.FIRST + 4: menu.setGroupEnabled(2, true); break; case Menu.FIRST + 5: menu.setGroupCheckable(2, true, true); break; case Menu.FIRST + 6: menu.setGroupCheckable(2, true, false); break; case Menu.FIRST + 7: Toast.makeText(this, "menu2_1", Toast.LENGTH_SHORT).show(); break; case Menu.FIRST + 8: Toast.makeText(this, "menu2_2", Toast.LENGTH_SHORT).show(); break; case Menu.FIRST + 10: Toast.makeText(this, "sub1", Toast.LENGTH_SHORT).show(); break; case Menu.FIRST + 11: Toast.makeText(this, "sub2", Toast.LENGTH_SHORT).show(); break; } return super.onOptionsItemSelected(item); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.textview: drawerLayout.openDrawer(leftDrawer); actionTextView.setText("左滑菜单"); break; case R.id.textview1: drawerLayout.openDrawer(rightDrawer); actionTextView.setText("右滑菜单"); break; case R.id.personal_textview: drawerLayout.openDrawer(rightDrawer); actionTextView.setText("右滑菜单"); break; case R.id.image_view: drawerLayout.openDrawer(leftDrawer); actionTextView.setText("左滑菜单"); break; } } }
最后得到效果如下图:
怎么样,是不是感觉还是很炫的,