ToolBar比ActionBar更加可控,自由。因此,Google 逐渐使用ToolBar来代替ActionBar。
转载请标明出处
使用ToolBar
1.要引入appCompat_v7支持
2.主题设置为NoActionBar
在style.xml文件中
给应用设置该主题 上面的style中有两个风格: 1、- @style/MySearchView
是在toolbar上面添加搜索框,所以还要再声明一个style,即搜索框的style。
//Android自带的搜索框
2、<item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item>是设置溢出菜单的风格。
- false
//背景色- @android:color/holo_blue_dark
//文字颜色- @android:color/white
//溢出菜单宽度- wrap_content
//溢出菜单高度- wrap_content
如图便可见溢出菜单,关于菜单配置接下来会讲
记住别忘了还要gradle里声明依赖
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:21.0.3'}
界面布局
请记得用 support v7 里的 toolbar,不然然只有 API Level 21 也就是 Android 5.0 以上的版本才能使用。
程序代码:
toolbar=(Toolbar) findViewById(R.id.toolbar);toolbar.setTitle("主标题");toolbar.setSubtitle("副标题");toolbar.setLogo(R.mipmap.ic_launcher);setSupportActionBar(toolbar);//把toolbar当成actionBar使用 toolbar.setNavigationIcon(R.drawable.ab_android);
这边要留意的是setNavigationIcon需要放在 setSupportActionBar之后才会生效。
菜单配置
结果图:
我们来讲解一下上面xml文件中的一些属性:
-
- orderInCategory
- 设置菜单项的排列顺序,必须设置大于等于0的整数值。数值小的排列在前,如果值相等,则按照xml中的顺序展现。
- title菜单项的标题。
- icon菜单项的图标。
- showAsAction该属性有五个值,可以混合使用。
- always总是显示在Toolbar上。
- ifRoom如果Toolbar上还有空间,则显示,否则会隐藏在溢出列表中。
- never永远不会显示在Toolbar上,只会在溢出列表中出现。
- withText文字和图标一起显示。
- collapseActionView声明了这个操作视窗应该被折叠到一个按钮中,当用户选择这个按钮时,这个操作视窗展开。一般要配合ifRoom一起使用才会有效。
接下来在程序中重写onCreateOptionsMenu,加载菜单
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.memu_prac_toolbar,menu); return true; }
菜单单击事件
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_error_ques: startActivity(new Intent(MainActivity.this, ErrorActivity.class)); break; case R.id.action_collected_ques: startActivity(new Intent(MainActivity.this, CollectedActivity.class)); break; default: return false; } return true; }
有时候会出现一个棘手的问题,那就是溢出菜单没法显示图标,我们可以用反射机制来解决该问题,代码如下:
/** * 运用反射机制解决toolBar溢出菜单无法显示图标的问题 * @param view * @param menu * @return */ @Override protected boolean onPrepareOptionsPanel(View view, Menu menu) { if (menu != null) { if (menu.getClass().getSimpleName().equals("MenuBuilder")) { try{ Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE); m.setAccessible(true); m.invoke(menu, true); } catch (Exception e) { Log.e(getClass().getSimpleName(), "onMenuOpened...unable to set icons for overflow menu", e); } } } return super.onPrepareOptionsPanel(view, menu); }
我们再假设一个场景:mainActivity里面有一个ViewPager和一个toolbar,ViewPager里面有几个Fragment,当fragment切换的时候要动态改变toolbar的菜单,那么我们应该怎么做呢?
我们都知道,我们在建立actionbar或是toolbar的时候,都会默认的实现两个方法,分别是onCreateOptionsMenu和onOptionsItemSelected,这两个方法,前面的是建立菜单,后面的对选中的菜单进行操作。onCreateOptionsMenu只会在第一次初始化菜单时调用,其后就不在运行了,也就是说它只一次加载完之后,就不会再动了,所以我们没法通过这个方法来改变toolbar的菜单。
Android给我们提供了一个onPrepareOptionsMenu(Menu menu)方法,我们可以在里面动态改变菜单,然后通过判断viewPager滑动到第几页,通过invalidateOptionsMenu()动态调用该方法。
/** * 根据memuPosition的值来选择加载的菜单 * @param menu * @return */ @Override public boolean onPrepareOptionsMenu(Menu menu) { menu.clear(); MenuInflater inflater=this.getMenuInflater(); switch (memuPosition) { case 0: case 3: inflater.inflate(R.menu.memu_prac_toolbar,menu);//答题界面的toolbar菜单 //如果只是想动态隐藏或者显示菜单控件的话可以用下面的方法。 //menu.findItem(R.id.search_button).setVisible(true); //menu.findItem(R.id.scan_button).setVisible(true); //menu.findItem(R.id.setting_button).setVisible(false); break; case 1: inflater.inflate(R.menu.memu_stu_toolbar,menu);//学习界面的toolbar菜单 break; case 2: inflater.inflate(R.menu.memu_forum_toolbar,menu);//论坛界面的toolbar菜单 break; default: break; } return super.onPrepareOptionsMenu(menu); }
我们要先清除之前的菜单,不然它会在之前的菜单基础上继续添加。
在viewPager滑动的时候进行判断,然后调用。
if(myViewPager.getCurrentItem()!=0){ myViewPager.setCurrentItem(0); toolbar.setTitle(re.getString(R.string.tv_answer)); memuPosition=0; //标识位于第几页 invalidateOptionsMenu();//重新加载菜单}
注意要调用invalidateOptionsMenu()或者supportInvalidateOptionMenu()方法。
既然已经用onPrepareOptionsMenu(Menu menu)来加载菜单了,那么activity中的
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.memu_prac_toolbar,menu); return true; } 可以不写,因为该方法便是来加载菜单的。 出了上面所将的这些,toolbar还有一些坑,那就是在fragment中使用的时候,继续上面的场景,我们再增加一种场景,那就是需要在fragment中响应菜单的点击事件,我们应该怎么做呢? 我们可以在fragment里面重写onOptionsItemSelected(MenuItem item),例如下面代码:
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_vertical_arrangement: //设置recycleView的布局方式为竖直线性布局 recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); break; case R.id.action_horizontal_arrangement: //设置recycleView的布局方式为网格布局 recyclerView.setLayoutManager(new GridLayoutManager(getContext(),2)); break; default: return super.onOptionsItemSelected(item); } return true; }
不过有一点需要很注意,那就是必须在onCreate里写上setHasOptionsMenu(true),这样子onOptionsItemSelected(MenuItem item)才有效。点击事件是由Activity的onOptionsItemSelected(MenuItem item)传进来的(事件分发)。
如果我们要在fragment中加载菜单,那么可以在fragment中重写onCreateOptionsMenu(Menu menu, MenuInflater inflater)
@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.memu_stu_toolbar,menu); super.onCreateOptionsMenu(menu, inflater); }
注意该方法与Activity中的public boolean onCreateOptionsMenu(Menu menu)是不一样的,activity中的有返回值。一样的必须在onCreate里写上setHasOptionsMenu(true),fragment里面的onCreateOptionsMenu(Menu menu, MenuInflater inflater)才会生效。
程序会先调用activity的public boolean onCreateOptionsMenu(Menu menu),再调用fragment里的onCreateOptionsMenu(Menu menu, MenuInflater inflater),如果fragment中没有对menu进行清除,那么fragment里的菜单会在Activity外的菜单基础上添加上去。
以上便是本人就项目过程中遇到的问题对toolbar的总结,以后要是遇到其他问题会继续补充。
转载请标明出处