Android界面编程——导航栏及菜单
2.7导航栏及菜单
2.7.1 ActionBar
ActionBar是Android3.0(API 11)开始增加的新特性,ActionBar出现在活动窗口的顶部,可以显示标题、icon、Actions按钮、可交互View,可实现应用程序级的导航,如图2.7-1所示
图2.7-1
其中
1、 App icon:
主要用于展示App的Logo,如果当前界面不是一级界面,还可以展示返回航。
2、View Control:
用于切换不同的视图或者展示非交互信息如app标题等。
3、Action Buttons:
用于展示app中最重要的操作按钮,如果过多actionbar中放不下则会转移到Action
overflow中,长按会展示操作名称。Action Buttons的总宽度不会超过ActionBar的50%。
4、Action overflow:用于存放展示相对较少使用的操作按钮。
明白了什么是ActionBar,下面我们来下看看ActionBar的兼容性和显示与隐藏
? ActionBar的兼容性
在android3.0或者以上版本中,ActionBar已经默认的包含在Activity中,不需要进行任何设置。对于在API
Level 11以下的版本使用actionBar
1、需要导入并使用v7支持包的ActionBar,android
studio Gradle的build.gradle文件已经加入,如下所示:
dependencies {
compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
testCompile ‘junit:junit:4.12‘
compile ‘com.android.support:appcompat-v7:23.1.1‘
compile ‘com.android.support:design:23.1.1‘
}
2、Activity必须使用Theme.AppCompat.Light主题样式,样式如下所示:
<style name="Theme.MyActionBar" parent="@style/Theme.AppCompat.Light">
…
</style>
? ActionBar的隐藏
由于ActionBar已经默认的包含在Activity中,如果要去除ActionBar有如下两种方法:
1、设置主题AppTheme.NoActionBar,实现为Activity去除掉ActionBar。
Style样式:
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
Activity应用主题样式:
<activity android:name=".MainActivity" android:theme="@style/AppTheme"/>
2、通过在代码中调用show()或者hide()方法来相应的显示或者隐藏ActionBar,代码如下:
//获得ActionBar
ActionBar actionBar=super.getSupportActionBar();
//隐藏ActionBar
actionBar.hide();
//显示ActionBar
//actionBar.show();
表2.7-1列出了ActionBar常用的方法
表2.7-1 ActionBar常用方法说明
方法 |
说明 |
setDisplayShowHomeEnabled(boolean) |
控制是否显示Home区域的显示,如果要显示Logo图片和Image图片,必须设置为true |
setDisplayHomeAsUpEnabled(boolean) |
控制是否显示回退按钮 |
setDisplayShowTitleEnabled(boolean) |
控制是否显示标题 |
setDisplayUseLogoEnabled(boolean) |
控制是否Logo图片 |
setTitle(CharSequence) |
设置标题 |
setLogo(int) |
设置Logo图片,与Icon不能同时使用 |
setIcon(int) |
设置Icon图片,与Logo不能同时使用 |
setHomeAsUpIndicator(int) |
改变回退按钮的图标,该方法要求Android API 18以上 |
下面就通过案例2.7-1,讲解ActionBar的基本用法,执行效果如图2.7-2
图2.7-2
2.7.2 菜单Menu
菜单是许多应用中常见的用户界面组件。可为用户带来熟悉而风格一致的用户体验 。从 Android 3.0(API 11)开始,采用 Android 设备不必再提供一个专用“菜单”按钮。随着这种改变,Android 应用不再提供对对包含 6 个项目的传统菜单面板的支持如图2.7-3,取而代之的是要提供一个操作栏(ActionBar或Toolbar)来呈现常见的用户操作,如图2.7-4。
图2.7-3
如图2.7-4
? 选项菜单与操作栏
选项菜单是某个
Activity 的主菜单项,提供对应用产生全局影响的操作,如“搜索”、“撰写电子邮件”和“设置”。
在 Android 3.0 及更高版本的系统中,操作栏以屏幕操作项和溢出选项的组合形式呈现选项菜单中的各项,具体体现在ActionBar右侧的Action
Buttons 和Action overflow区域
选项菜单的实现步骤:
1、创建菜单,在 res/menu/ 目录内创建一个XML
文件,示例如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/new_game"
android:icon="@drawable/ic_new_game"
android:title="@string/new_game"
android:showAsAction="ifRoom"/>
<item android:id="@+id/help"
android:icon="@drawable/ic_help"
android:title="@string/help" />
</menu>
属性说明:
android:id:菜单标识ID。
android:icon:设置菜单项的图标。
android:title:设置菜单项的文本。
android:showAsAction: ifRoom、never、always、withText、collapseActionView,五个属性值可以混合使用。
ifRoom:会显示在ActionBar右侧Buttons区域,当数量超出屏幕的允许的空间范围会隐藏到OverFlow中去
never:在溢出列表中显示
always:无论是否溢出,总会在显示ActionBar上显示。
withText:在Action bar上显示文本标题
collapseActionView:操作视窗被折叠到一个按钮中,当用户选择这个按钮时,这个操作视窗展开。要配合ifRoom一起使用才会有效果。
2、重写Activity的onCreateOptionsMenu()方法,产生选项菜单
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();//获得菜单转换器
inflater.inflate(R.menu.game_menu, menu);//将Menu资源转换成系统菜单
return true;
}
3、处理菜单点击事件,重写Activity的onOptionsItemSelected()方法
代码片段如下:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {//判断选项菜单的ID,点击不同的菜单执行不同的功能
case R.id.new_game:
newGame();
return true;
case R.id.help:
showHelp();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
接下在通过案例2.7-2实现选项菜单与ActionBar的应用,如图2.7-5所示:
图2.7-5
public class OptionMenuActionBarActivity extends AppCompatActivity { private ActionBar actionBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_simple_action_bar); //获得ActionBar actionBar=super.getSupportActionBar(); initActionBar(); } private void initActionBar(){ //显示Home区域 actionBar.setDisplayShowHomeEnabled(true); //显示回退按钮 actionBar.setDisplayHomeAsUpEnabled(true); //改变回退按钮的图标,该方法要求Android 18以上 // actionBar.setHomeAsUpIndicator //(R.mipmap.btn_back_detail_normal_night); //显示标题 actionBar.setDisplayShowTitleEnabled(true); actionBar.setTitle("杰瑞教育");//设置title //显示Logo图片,与ICon图标两者不能同时使用 actionBar.setDisplayUseLogoEnabled(false); actionBar.setLogo(R.mipmap.sun);//设置logo图片 //设置Icon图标,与Logo图片两者不能同时使用 actionBar.setIcon(R.mipmap.ic_launcher); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.action_bar, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()){ //系统为ActionBar的回退键定义的ID case android.R.id.home: //当点击回退键,返回到上一页面 super.onBackPressed(); break; //匹配“查询”选项菜单 case R.id.action_search: Toast.makeText(this, "查询", Toast.LENGTH_SHORT).show(); break; //匹配“收藏”选项菜单 case R.id.action_collection: Toast.makeText(this, "收藏", Toast.LENGTH_SHORT).show(); break; } return super.onOptionsItemSelected(item); } }
? 创建上下文菜单ContextMenu
上下文菜单提供为UI控件了快捷操作,方便用户的使用并节省了空间。可以为任何视图提供上下文菜单,但这些菜单通常用于ListView、GridView等适配器控件,方便用户对集合信息中的某一项进行操作。
提供上下文操作的方法有两种如图2.7-6所示:
图 2.7-6浮动上下文菜单(左)和上下文操作栏(右)的屏幕截图。
2 使用“浮动上下文”菜单。
用户长按(按住)一个注册支持上下文菜单的视图时,弹出一个类似于对话框的浮动菜单。用户一次可对一个项目执行上下文操作。
接下在通过案例2.7-3实现浮动上下文菜单应用,如图2.7-7所示:
图2.7-7
public class MenuContextActivity extends AppCompatActivity { //列表项数据 String[] messages={"20160111一个信息","20160211一个信息","20160212一个信息", "20160311一个信息","20160411一个信息"}; private ListView lvMessage; private ArrayAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_menu_context); lvMessage=(ListView)super.findViewById(R.id.lvMessage); initView(); } private void initView(){ //创建适配器 adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,messages); lvMessage.setAdapter(adapter); //调用Activity的registerForContextMenu()将上下文菜单与ListView关联 super.registerForContextMenu(lvMessage); } /** * 产生上下文菜单 */ @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); //创建菜单转换器 MenuInflater inflater = getMenuInflater(); //通过MenuInflater菜单转换器生成菜单 inflater.inflate(R.menu.context_menu, menu); } /** * 响应用户单击上下文菜单的操作 * @param item 用户操作的菜单项 */ @Override public boolean onContextItemSelected(MenuItem item) { //当用户操作AdapterView 的上下文菜单时,为onContextItemSelected()回调函数提供的AdapterView相关信息。 // 例如本例中,用户在ListView中的某一项长按时弹出浮动上下文菜单,AdapterContextMenuInfo中就包含了 // ListView的当前这个选项的信息 //AdapterContextMenuInfo主要属性 // id:用于获得上下文菜单的子视图的行 ID。 // position:用于获得上下文菜单的子视图在适配器中的位置。 // targetView:用于获得上下文菜单的子视图。 AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); String mess=messages[info.position]; switch (item.getItemId()) { case R.id.action_add: Toast.makeText(this, "执行添加", Toast.LENGTH_SHORT).show(); return true; case R.id.action_delete: Toast.makeText(this, "删除"+mess, Toast.LENGTH_SHORT).show(); return true; case R.id.action_update: Toast.makeText(this, "更新"+mess, Toast.LENGTH_SHORT).show(); return true; default: return super.onContextItemSelected(item); } } }
小结:“浮动上下文”菜单的实现步骤:
1、在menu资源中,创建menu菜单。
2、重写Activity的onCreateContextMenu()方法。
3、重写Activity的onContextItemSelected()方法。
4、调用Activity的registerForContextMenu()将上下文菜单与View关联。
5、如果使用适配控件与ContextMenu关联,在回调方法onContextItemSelected()中通过AdapterContextMenuInfo获得适配控件当前选项信息。
2 使用“上下文操作”模式。
此模式是 ActionMode 的系统实现,它将在屏幕顶部显示上下文操作栏,其中包含影响所选项的操作菜单。当此模式处于活动状态时,用户可以同时对多项执行操作。
接下来通过案例2.7-4 实现ListView启用“上下文操作”模式,如图2.7-7所示:
图2.7-7
实现步骤:
1、实现 AbsListView.MultiChoiceModeListener 接口。
使用 setMultiChoiceModeListener() 为视图组设置该接口。在侦听器的回调方法中,可以为上下文操作栏指定操作菜单,可以响应操作项目的点击事件,还可以处理从 ActionMode.Callback 接口继承的其他回调。
2、使用 CHOICE_MODE_MULTIPLE_MODAL 参数调用 setChoiceMode()。
3、调用ListView的 setChoiceMode()方法设置选项模式为
CHOICE_MODE_MULTIPLE_MODAL
public class ActionModeMenuActivity extends AppCompatActivity { String[] messages={"20160111一个信息","20160211一个信息","20160212一个信息", "20160311一个信息","20160411一个信息"}; private ListView lvMessage; private ArrayAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_menu_context); lvMessage=(ListView)super.findViewById(R.id.lvMessage); initView(); } private void initView(){ adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,messages); lvMessage.setAdapter(adapter); //设置选项模式为CHOICE_MODE_MULTIPLE_MODAL lvMessage.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); //实现MultiChoiceModeListener接口,并注册MultiChoiceModeListener侦听 lvMessage.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() { private int position; //通过该回调方法可以获得所操作的列表项的Id,索引,选择状态 /** * 当选项状态发生变化时回调该方法 * 通过该回调方法可以获得所操作的列表项的Id,索引,选择状态 * @param mode * @param position 所操作的列表项的索引 * @param id 所操作的列表项的Id * @param checked 选择状态 */ @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { Log.d("jereh","onItemCheckedStateChanged is called"); this.position=position; } /** * 回调该方法创建“上下文操作”栏 * @param mode * @param menu 操作栏菜单 * @return */ @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { Log.d("jereh","onCreateActionMode is called"); //菜单转换器 MenuInflater inflater = getMenuInflater(); //根据xml转换产生menu组件,并放置到“上下文操作”栏 inflater.inflate(R.menu.context_menu2, menu); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { Log.d("jereh","onPrepareActionMode is called"); return false; } /** * 单击操作栏的菜单项时调用,用于响应菜单栏操作 * @param mode * @param item 单击的菜单项 * @return */ @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { String mess=messages[position]; Log.d("jereh","onActionItemClicked is called"); //根据菜单项ID,判断单击的是哪个菜单项。 switch (item.getItemId()){ case R.id.action_delete: Toast.makeText(ActionModeMenuActivity.this,"删除"+mess, Toast.LENGTH_SHORT).show(); break; case R.id.action_update: Toast.makeText(ActionModeMenuActivity.this, "更新"+mess, Toast.LENGTH_SHORT).show(); break; } return false; } @Override public void onDestroyActionMode(ActionMode mode) { mode=null; } }); } }
? 创建弹出式菜单PopupMenu
PopupMenu 是锚定到 View 的模态菜单。如果空间足够,它将显示在定位视图下方,否则显示在其上方。它适用于:
为特定的内容提供相关操作的溢出样式菜单。例如,单击Gmail 的电子邮件标头弹出如图 2.7-8 所示的菜单。
图 2.7-8
注:上下文菜单不同,PopupMenu提供执行不影响所选内容的操作菜单,而ContextMenu通常用于影响所选内容的操作。 对于影响所选内容的操作,请使用上下文操作模式或浮动上下文菜单。而注:PopupMenu 在API
11 及更高版本中可用。
PopupMen的方法如下:
1、实例化 PopupMenu ,将菜单应锚定到相关的 View上。
2、使用 MenuInflater 将菜单资源扩充到 PopupMenu.getMenu() 返回的 Menu 对象中。在API
14 及更高版本中,可以改为使用 PopupMenu.inflate()。
3、调用 PopupMenu.show()。
接下在通过案例2.7-5 实现ListView启用“上下文操作”模式,如图2.7-9所示:
图2.7-9
2.7.3 ToolBar
本章节学习使用 V7 appcompat支持库的ToolBar插件实现应用栏。通过Actionbar的学习我们知道从Android 3.0(API 11)开始,所有Activity使用默认主题的ActionBar作为一个应用程序的统一标题栏。但是ActionBar在不同的Android版?、不同的设备的表现不同,存在兼容性的问题。相比之下,最新的版的支持库(v7appcompat)中提供的ToolBar组件具有很好的兼容性,可以很好的解决这一问题。出于这个原因,Google推荐使用支持库的Toolbar来取代ActionBar实现应用程序标题栏。
ToolBar与ActionBar相比具备以下优越性:
? 使用支持库的ToolBar有助于确保应用程序在最大范围的设备一致性。
? 可以为应用程序开发的自定义应用程序栏,更加灵活。
在Activity中加入Toolbar的步骤:
1、添加的 appcompat V7支持库到您的项目。
android studio默认已经为项目添加了V7支持库,打开Gradle的build.gradle文件,如下所示:
dependencies {
compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
testCompile ‘junit:junit:4.12‘
compile ‘com.android.support:appcompat-v7:23.1.1‘
compile ‘com.android.support:design:23.1.1‘
}
2、编写Activity继承AppCompatActivity
public class ToolBarDemoActivity extends AppCompatActivity {
// ...
}
3、通过代码或主题样式去除Activity的ActionBar
<activity
android:name=".ToolBarDemoActivity"
android:label="@string/title_activity_tool_bar_demo"
android:theme="@style/AppTheme.NoActionBar" />
4、在Activity的布局文件中,添加ToolBar。
<android.support.v7.widget.Toolbar
android:id = "@+id/my_toolbar"
android:layout_width = "match_parent"
android:layout_height = "?attr/actionBarSize"
android:background = "?attr/colorPrimary"
android:elevation = "4dp"
android:theme = "@style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme = "@style/ThemeOverlay.AppCompat.Light" />
5、在Activity的的onCreate() 方法引用Toolbar组件,调用Activity对的setSupportActionBar()方法设置将Toolbar设置的Activity中。
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate ( savedInstanceState );
setContentView ( R . layout . activity_my );
Toolbar myToolbar = ( Toolbar ) findViewById ( R . id . my_toolbar );
setSupportActionBar ( myToolbar );
}
表2.7-2 Toolbar常用方法及其作用。
表2.7-2 Toolbar方法和作用
方法 |
作用 |
setNavigationIcon(int) |
设置工具栏的回退图标 |
setLogo(int) |
设置工具栏logo图片 |
setTitle(CharSequence) |
设置工具栏标题 |
setSubtitle(CharSequence) |
设置工具栏子标题 |
接下在通过案例2.7-6 实现如图2.7-10所示应用效果:
图2.7-10
? 向Toolbar添加Action Buttons和Overflow Menu
同Actionbar一样也可以通过重写Activity的onCreateOptionsMenu()向Toolbar添加Action
Buttons和Overflow Menu对用户操作,并且通过重写onOptionsItemSelected()响应用户的操作
接下在上一案例的基础实现案例2.7-7 实现如图2.7-11所示应用效果:
图2.7-11
? 向Toolbar添加Action View和Action Providers
Toolbar提供了多种不同的方式用户和应用程序进行交互。前面的章节描述如何定义一个Action Buttons和Overflow Menu。章节介绍在Toolbar实现两个通用的组件:
1、Action View,它提供了Toolbar内更丰富的功能操作。例如,搜索Action View允许用户在应用栏键入搜索文本,无需添加任何代码。
2、Action Provider,可以为Action提供自定制的布局。初始显示为一个按钮或菜单项,但是当用户点击时,则会显示Action
Providers提供的自定制的布局。
Android的支持库提供一些专门的Action View和Action Provider部件。例如,所述SearchView插件实现用于输入搜索查询的动作视图,ShareActionProvider插件实现一个Action
Provider与其他应用程序共享信息。您也可以定义自己的行动的Action View和Action Provider。
接下在通过案例2.7-8 实现如图2.7-11所示应用效果:
图2.7-11
Android版本库中提供ShareActionProvider组件,它继承自Action Provider
可以高效的、友好的实现各种分享操作,可以和Toolbar结合使用。注意使用该组件必须为ShareActionProvider提供一个Share
Intent,下面结合Toolbar介绍使用ShareActionProvider的基本步骤:
1、获得ShareActionProvider,通过调用getActionProvider(),并通过该共享操作的 菜单项。代码:
MenuItem shareItem = menu . findItem ( R . id . action_share );
ShareActionProvider myShareActionProvider =
( ShareActionProvider ) MenuItemCompat . getActionProvider ( shareItem );
2、创建具有ACTION_SEND 动作的Intent,并附加了共享的内容。代码:
Intent myShareIntent = new Intent ( Intent . ACTION_SEND );
myShareIntent . setType ( "image/*" );
myShareIntent . putExtra ( Intent . EXTRA_STREAM , myImageUri );
Intent内容参考第十章相关内容
3、调用setShareIntent()这个方法将Intent附加到ActionProvider:
myShareActionProvider.setShareIntent(myShareIntent);
4、当内容发生变化,修改Intent或创建一个新的,并调用重新setShareIntent()方法:
myShareIntent.putExtra(Intent.EXTRA_STREAM, myNewImageUri);
myShareActionProvider.setShareIntent(myShareIntent);
接下在通过案例2.7-9 实现如图2.7-12所示应用效果:
图2.7-12
作者:冲天之峰 20160713