【转】Android ActionBar完全解析,使用官方推荐的最佳导航栏(上)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/18234477
本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文。
http://developer.android.com/guide/topics/ui/actionbar.html
Action Bar是一种新増的导航栏功能,在Android 3.0之后加入到系统的API当中,它标识了用户当前操作界面的位置,并提供了额外的用户动作、界面导航等功能。使用ActionBar的好处是,它可以 给提供一种全局统一的UI界面,使得用户在使用任何一款软件时都懂得该如何操作,并且ActionBar还可以自动适应各种不同大小的屏幕。下面是一张使 用ActionBar的界面截图:
其中,[1]是ActionBar的图标,[2]是两个action按钮,[3]是overflow按钮。
由于Action Bar是在3.0以后的版本中加入的,如果想在2.x的版本里使用ActionBar的话则需要引入Support Library,不过3.0之前版本的市场占有率已经非常小了,这里简单起见我们就不再考虑去做向下兼容,而是只考虑4.0以上版本的用法。
添加和移除Action Bar
ActionBar 的添加非常简单,只需要在AndroidManifest.xml中指定Application或Activity的theme是Theme.Holo或 其子类就可以了,而使用Eclipse创建的项目自动就会将Application的theme指定成Theme.Holo,所以ActionBar默认 都是显示出来的。新建一个空项目并运行,效果如下图所示:
而如果想要移除ActionBar的话通常有两种方式,一是将theme指定成Theme.Holo.NoActionBar,表示使用一个不包含ActionBar的主题,二是在Activity中调用以下方法:
ActionBar actionBar = getActionBar();
actionBar.hide();
现在重新运行一下程序,就可以看到ActionBar不再显示了,如下图所示:
修改Action Bar的图标和标题
默 认情况下,系统会使用<application>或者<activity>中icon属性指定的图片来作为ActionBar的 图标,但是我们也可以改变这一默认行为。如果我们想要使用另外一张图片来作为ActionBar的图标,可以在<application>或 者<activity>中通过logo属性来进行指定。比如项目的res/drawable目录下有一张weather.png图片,就可以 在AndroidManifest.xml中这样指定:>
<activity
android:name="com.example.actionbartest.MainActivity"
android:logo="@drawable/weather" >
</activity>
现在重新运行一下程序,效果如下图所示:
OK,ActionBar的图标已经修改成功了,那么标题中的内容该怎样修改呢?其实也很简单,使用label属性来指定一个字符串就可以了,如下所示:
<activity
android:name="com.example.actionbartest.MainActivity"
android:label="天气"
android:logo="@drawable/weather" >
</activity>
添加Action按钮
那么我们先来看下menu资源文件该如何定义,代码如下所示:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.actionbartest.MainActivity" > <item
android:id="@+id/action_compose"
android:icon="@drawable/ic_action_compose"
android:showAsAction="always"
android:title="@string/action_compose"/>
<item
android:id="@+id/action_delete"
android:icon="@drawable/ic_action_delete"
android:showAsAction="always"
android:title="@string/action_delete"/>
<item
android:id="@+id/action_settings"
android:icon="@drawable/ic_launcher"
android:showAsAction="never"
android:title="@string/action_settings"/> </menu>
可以看到,这里我们通过三个<item>标签定义了三个Action按 钮。<item>标签中又有一些属性,其中id是该Action按钮的唯一标识符,icon用于指定该按钮的图标,title用于指定该按钮 可能显示的文字(在图标能显示的情况下,通常不会显示文字),showAsAction则指定了该按钮显示的位置,主要有以下几种值可选:always表 示永远显示在ActionBar中,如果屏幕空间不够则无法显示,ifRoom表示屏幕空间够的情况下显示在ActionBar中,不够的话就显示在 overflow中,never则表示永远显示在overflow中。接着,重写Activity的onCreateOptionsMenu()方法,代码如下所示:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
这部分代码很简单,仅仅是调用了MenuInflater的inflate()方法来加载menu资源就可以了。现在重新运行一下程序,结果如下图所示:
- 当ActionBar中的剩余空间不足的时候,如果Action按钮指定的showAsAction属性是ifRoom的话,该Action按钮就会出现在overflow当中,此时就只有title能够显示了。
- 如果Action按钮在ActionBar中显示,用户可能通过长按该Action按钮的方式来查看到title的内容。
响应Action按钮的点击事件
当 用户点击Action按钮的时候,系统会调用Activity的onOptionsItemSelected()方法,通过方法传入的MenuItem参 数,我们可以调用它的getItemId()方法和menu资源中的id进行比较,从而辨别出用户点击的是哪一个Action按钮,比如:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_compose:
Toast.makeText(this, "Compose", Toast.LENGTH_SHORT).show();
return true;
case R.id.action_delete:
Toast.makeText(this, "Delete", Toast.LENGTH_SHORT).show();
return true;
case R.id.action_settings:
Toast.makeText(this, "Settings", Toast.LENGTH_SHORT).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
可以看到,我们让每个Action按钮被点击的时候都弹出一个Toast,现在重新运行一下代码,结果如下图所示:
通过Action Bar图标进行导航
我们可以通过调用setDisplayHomeAsUpEnabled()方法来启用ActionBar图标导航功能,比如:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("天气");
setContentView(R.layout.activity_main);
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
现在重新运行一下程序,结果如下图所示:
可以看到,在ActionBar图标的左侧出现了一个向左的箭头,通常情况下这都表示返回的意思,因此最简单的实现就是在它的点击事件里面加入finish()方法就可以了,如下所示:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
……
}
}
当点击ActionBar图标的时候,系统同样会调用onOptionsItemSelected()方法,并且此时的itemId是android.R.id.home,所以finish()方法也就是加在这里的了。
第二步需要在AndroidManifest.xml中配置父Activity,如下所示:
<activity
android:name="com.example.actionbartest.MainActivity"
android:logo="@drawable/weather" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.actionbartest.LaunchActivity" />
</activity>
可以看到,这里通过meta-data标签指定了MainActivity的父Activity是LaunchActivity,在Android 4.1版本之后,也可以直接使用android:parentActivityName这个属性来进行指定,如下所示:
<activity
android:name="com.example.actionbartest.MainActivity"
android:logo="@drawable/weather"
android:parentActivityName="com.example.actionbartest.LaunchActivity" >
</activity>
第三步则需要对android.R.id.home这个事件进行一些特殊处理,如下所示:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
TaskStackBuilder.create(this)
.addNextIntentWithParentStack(upIntent)
.startActivities();
} else {
upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
NavUtils.navigateUpTo(this, upIntent);
}
return true;
......
}
}
其中,调用NavUtils.getParentActivityIntent()方法 可以获取到跳转至父Activity的Intent,然后如果父Activity和当前Activity是在同一个Task中的,则直接调用 navigateUpTo()方法进行跳转,如果不是在同一个Task中的,则需要借助TaskStackBuilder来创建一个新的Task。
添加Action View
为了声明一个ActionView,我们可以在menu资源中通过actionViewClass属性来指定一个控件,例如可以使用如下方式添加SearchView:
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <item
android:id="@+id/action_search"
android:icon="@drawable/ic_action_search"
android:actionViewClass="android.widget.SearchView"
android:showAsAction="ifRoom|collapseActionView"
android:title="@string/action_search" />
...... </menu>
注意在showAsAction属性中我们还声明了一个collapseActionView,这个值表示该控件可以被合并成一个Action按钮。
如果你还希望在代码中对SearchView的属性进行配置(比如添加监听事件等),完全没有问题,只需要在onCreateOptionsMenu()方法中获取该ActionView的实例就可以了,代码如下所示:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
// 配置SearchView的属性
......
return super.onCreateOptionsMenu(menu);
}
在得到了SearchView的实例之后,就可以任意地配置它的各种属性了。关于SearchView的更多详细用法,可以参考官方文档 http://developer.android.com/guide/topics/search/search-dialog.html 。除此之外,有些程序可能还希望在ActionView展开和合并的时候显示不同的界面,其实我们只需要去注册一个ActionView的监听器就能实现这样的功能了,代码如下所示:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
searchItem.setOnActionExpandListener(new OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
Log.d("TAG", "on expand");
return true;
} @Override
public boolean onMenuItemActionCollapse(MenuItem item) {
Log.d("TAG", "on collapse");
return true;
}
});
return super.onCreateOptionsMenu(menu);
}
可以看到,调用MenuItem的 setOnActionExpandListener()方法就可以注册一个监听器了,当SearchView展开的时候就会回调 onMenuItemActionExpand()方法,当SearchView合并的时候就会调用 onMenuItemActionCollapse()方法,我们在这两个方法中进行相应的UI操作就可以了。
Overflow按钮不显示的情况
实 际上,在ViewConfiguration这个类中有一个叫做sHasPermanentMenuKey的静态变量,系统就是根据这个变量的值来判断手 机有没有物理Menu键的。当然这是一个内部变量,我们无法直接访问它,但是可以通过反射的方式修改它的值,让它永远为false就可以了,代码如下所 示:
@Override
protected void onCreate(Bundle savedInstanceState) {
......
setOverflowShowingAlways();
} private void setOverflowShowingAlways() {
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
} catch (Exception e) {
e.printStackTrace();
}
}
这里我们在onCreate()方法的最后调用了setOverflowShowingAlways()方法,而这个方法的内部就是使用反射的方式将sHasPermanentMenuKey的值设置成false,现在重新运行一下代码,结果如下图所示:
让Overflow中的选项显示图标
其 实,overflow中的Action按钮应不应该显示图标,是由MenuBuilder这个类的setOptionalIconsVisible方法来 决定的,如果我们在overflow被展开的时候给这个方法传入true,那么里面的每一个Action按钮对应的图标就都会显示出来了。调用的方法当然 仍然是用反射了,代码如下所示:
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
if (featureId == Window.FEATURE_ACTION_BAR && 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) {
}
}
}
return super.onMenuOpened(featureId, menu);
}
可以看到,这里我们重写了一个onMenuOpened()方法,当overflow被展开的时候就会回调这个方法,接着在这个方法的内部通过返回反射的方法将MenuBuilder的setOptionalIconsVisible变量设置为true就可以了。
【转】Android ActionBar完全解析,使用官方推荐的最佳导航栏(上)的更多相关文章
- Android ActionBar完全解析,使用官方推荐的最佳导航栏(上)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/18234477 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工 ...
- Android ActionBar全然解析,使用官方推荐的最佳导航栏(上)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/18234477 本篇文章主要内容来自于Android Doc.我翻译之后又做了些加工 ...
- Android ActionBar完全解析,使用官方推荐的最佳导航栏(下) .
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/25466665 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工 ...
- Android DiskLruCache完全解析,硬盘缓存的最佳方案
Android DiskLruCache完全解析,硬盘缓存的最佳方案 概述 记得在很早之前,我有写过一篇文章Android高效加载大图.多图解决方案,有效避免程序OOM,这篇文章是翻译自Andro ...
- 【Android - 自定义View】之自定义颜色渐变的Tab导航栏
首先来介绍一下这个自定义View: (1)这个自定义View的名称叫做 GradientTab ,继承自View类: (2)这个自定义View实现了颜色渐变的Tab导航栏(仿微信主菜单),用户在左右滑 ...
- Android DiskLruCache完全解析,硬盘缓存的最佳方案(转)
概述 记得在很早之前,我有写过一篇文章<Android高效加载大图.多图解决方案,有效避免程序OOM>,这篇文章是翻译自Android Doc的,其中防止多图OOM的核心解决思路就是使用L ...
- (转)Android DiskLruCache完全解析,硬盘缓存的最佳方案
摘自:http://blog.csdn.net/guolin_blog/article/details/28863651 转载请注明出处: http://blog.csdn.net/guolin_bl ...
- Android DiskLruCache完全解析,硬盘缓存的最佳方案 --转载
概述 记得在很早之前,我有写过一篇文章 Android高效加载大图.多图解决方案,有效避免程序OOM,这篇文章是翻译自Android Doc的,其中防止多图OOM的核心解决思路就是使用LruCache ...
- Android DiskLruCache全然解析,硬盘缓存的最佳方案
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/28863651 概述 记得在非常早之前.我有写过一篇文章Android高效载入大图. ...
随机推荐
- 使用Spring和Tomcat发布CXF REST WebService
与发布SOAP WS一样, 同样需要在web.xml文件中配置CXFServlet: <!--cxf的Servlet--> <servlet> <servlet-name ...
- Intellij idea run dashboard面板
IDEA下 Spring Boot显示 Run Dashboard面板 Run Dashboard面板允许您一次浏览和管理多个运行项目,左侧是运行配置表及其状态,右侧是详细信息和特定于应用程序的信息, ...
- java代码switch语句求分数等级
总结:从键盘输入分数----- 如果在0到100内,则输出等级 小于0或者是大于100都不能输出,这里用if-else条件判断. package com.c2; import java.util.Sc ...
- Vue.js:循环语句
ylbtech-Vue.js:循环语句 1.返回顶部 1. 循环语句 循环使用 v-for 指令. v-for 指令需要以 site in sites 形式的特殊语法, sites 是源数据数组并且 ...
- python开发mysql:mysql数据类型&约束条件
一 整形 只有Int类型跟存储没有关系,显示的是宽度,其他类型都是限制 整形类型:[(m)][unsigned][zerofill] 作用:存储年龄,等级,id,各种号码 m,代表显示宽度 默认11 ...
- hibernate缓存机制详细介绍
hibernate的缓存机制,包括一级缓存(session级别).二级缓存(sessionFactory级别). 一:hibernate的 N+1问题 list()获得对象: 如果通过list()方法 ...
- oracle导入数据和编码问题
配置contrl文件 load data characterset utf8 append into table role_res_gold fields terminated by ';' TRAI ...
- 浅层神经网络 反向传播推导:MSE softmax
基础:逻辑回归 Logistic 回归模型的参数估计为什么不能采用最小二乘法? logistic回归模型的参数估计问题不能“方便地”定义“误差”或者“残差”. 对单个样本: 第i层的权重W[i]维度的 ...
- ulimit open files linux打开文件数设置验证
#include <stdio.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h ...
- Java微信公众平台开发(十一)--开发中微信公众平台/开放平台/商户平台的关联
转自:http://www.cuiyongzhi.com/post/55.html 微信公众平台(map.weixin.qq.com)/开放平台(open.weixin.qq.com)/商户平台(pa ...