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]是两个actionbutton,[3]是overflowbutton。
因为Action Bar是在3.0以后的版本号中加入的。假设想在2.x的版本号里使用ActionBar的话则须要引入Support Library,只是3.0之前版本号的市场占有率已经很小了,这里简单起见我们就不再考虑去做向下兼容,而是仅仅考虑4.0以上版本号的使用方法。
加入和移除Action Bar
ActionBar的加入很easy,仅仅须要在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不再显示了,例如以下图所看到的:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />
改动Action Bar的图标和标题
<activity
android:name="com.example.actionbartest.MainActivity"
android:logo="@drawable/weather" >
</activity>
如今又一次执行一下程序,效果例如以下图所看到的:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />
<activity
android:name="com.example.actionbartest.MainActivity"
android:label="天气"
android:logo="@drawable/weather" >
</activity>
加入Actionbutton
当然,假设button过多,ActionBar上显示不完。多出的一些button能够隐藏在overflow里面(最右边的三个点就是overflowbutton)。点击一下overflowbutton就能够看到全部的Actionbutton了。
<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>标签定义了三个Actionbutton。<item>标签中又有一些属性,其中id是该Actionbutton的唯一标识符。icon用于指定该button的图标,title用于指定该button可能显示的文字(在图标能显示的情况下,通常不会显示文字)。showAsAction则指定了该button显示的位置。主要有下面几种值可选:always表示永远显示在ActionBar中,假设屏幕空间不够则无法显示。ifRoom表示屏幕空间够的情况下显示在ActionBar中,不够的话就显示在overflow中,never则表示永远显示在overflow中。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
这部分代码很easy,仅仅是调用了MenuInflater的inflate()方法来载入menu资源就能够了。如今又一次执行一下程序,结果例如以下图所看到的:
- 当ActionBar中的剩余空间不足的时候,假设Actionbutton指定的showAsAction属性是ifRoom的话。该Actionbutton就会出如今overflow其中,此时就仅仅有title能够显示了。
- 假设Actionbutton在ActionBar中显示,用户可能通过长按该Actionbutton的方式来查看到title的内容。
响应Actionbutton的点击事件
@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);
}
}
能够看到,我们让每一个Actionbutton被点击的时候都弹出一个Toast,如今又一次执行一下代码。结果例如以下图所看到的:
通过Action Bar图标进行导航
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("天气");
setContentView(R.layout.activity_main);
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
如今又一次执行一下程序,结果例如以下图所看到的:
@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()方法也就是加在这里的了。
没错,假设我们仅仅是简单地finish了一下。ActionBar导航和Back键的功能是全然一样的,但ActionBar导航的设计初衷并非这种,它和Back键的功能还是有一些差别的。举个样例吧。
而ActionBar导航则不应该表现出这种行为,不管我们当前在哪一个Conversation details界面。点击一下导航button都应该回到Conversation List界面才对。
<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
<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,这个值表示该控件能够被合并成一个Actionbutton。
@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 。
@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操作就能够了。
Overflowbutton不显示的情况
比方我们启动一个有Menu键的模拟器。然后将代码执行到该模拟器上,结果例如以下图所看到的:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />
那么此时我们怎样查看隐藏在overflow中的Actionbutton呢?事实上很easy,按一下Menu键,隐藏的内容就会从底部出来了,例如以下图所看到的:
@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中的选项显示图标
@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全然解析,硬盘缓存的最佳方案
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/28863651 概述 记得在非常早之前.我有写过一篇文章Android高效载入大图. ...
- Android IntentService全然解析 当Service遇到Handler
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/47143563: 本文出自:[张鸿洋的博客] 一 概述 大家都清楚.在Andro ...
- Android DiskLruCache完全解析,硬盘缓存的最佳方案
Android DiskLruCache完全解析,硬盘缓存的最佳方案 概述 记得在很早之前,我有写过一篇文章Android高效加载大图.多图解决方案,有效避免程序OOM,这篇文章是翻译自Andro ...
- Android Volley全然解析(四),带你从源代码的角度理解Volley
版权声明:本文出自郭霖的博客,转载必须注明出处. https://blog.csdn.net/sinyu890807/article/details/17656437 转载请注明出处:http://b ...
- 【Android - 自定义View】之自定义颜色渐变的Tab导航栏
首先来介绍一下这个自定义View: (1)这个自定义View的名称叫做 GradientTab ,继承自View类: (2)这个自定义View实现了颜色渐变的Tab导航栏(仿微信主菜单),用户在左右滑 ...
- Android ViewDragHelper全然解析 自己定义ViewGroup神器
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/46858663. 本文出自:[张鸿洋的博客] 一.概述 在自己定义ViewGro ...
随机推荐
- snmp自定义OID与文件下载----服务器端配置
客户端使用命令工具:snmpwalk 服务端开启服务 snmp service.下载安装 net-snmp. 最近做了一些工作,记性较差感觉还是记下来比较好,毕竟网上能查到的有用的资料太少了. 自定义 ...
- 如何在 Linux 服务器上部署多个 Tomcat
开发管理项目时多多少少会遇到服务器不够用.一个项目分成多个子项目的情况,故研究了一下如何在一台服务器部署多个 Tomcat. 具体操作: 1.在 /tomcat/ 下部署多个 tomcat. 2.修改 ...
- [转]RabbitMQ学习之:(十二)在Node.js环境下使用RabbitMQ
本文转自:https://blog.csdn.net/puncha/article/details/8452017 学,以致用.找了半天Node.js下RabbitMQ的库,看上去都不太趁手,直到最后 ...
- MSSQL存储过程应用
1.原始表inoutinfo 2.现在想输入时间范围和操作类型输出对应的结果 2.1创建存储过程 create proc selecttype@type nvarchar(10),@starttime ...
- C#---初学ActiveMQ中间件
本篇文章只适合跟我一样的初学者,因为现阶段的我们只想者怎么实现功能,不太会去考虑潜在异常.从上周开始优化公司的调控系统,原先采取的都是通过操作数据库去实现功能,客户体验效果不佳,经过领导决定是用中间件 ...
- 【原】继承AbstractRoutingDataSource再通过AOP实现动态数据源切换
关于AbstractRoutingDataSource动态切换数据源是我在研究某开源项目时候才注意到的,大概就看懂了Spring AOP切面这里,根据作者的意思是通过继承这个抽象类可以实现数据源的动态 ...
- a标签禁止跳转或者不跳转的几种实现方式
1.onclick事件中返回false <a href="http://www.baidu.com" onclick="return false" &g ...
- 洛谷P3721 [AH2017/HNOI2017]单旋(线段树 set spaly)
题意 题目链接 Sol 这题好毒瘤啊.. 首先要观察到几个性质: 将最小值旋转到根相当于把右子树变为祖先的左子树,然后将原来的根变为当前最小值 上述操作对深度的影响相当于右子树不变,其他的位置-1 然 ...
- 【读书笔记】iOS-UDID
UIDevice类可以返回当前iOS设备的UDID,以前开发者通常使用UDID作为识别每台设备的唯一标识,然后从iOS5开始,苹果公司将这一功能标记为废止并不推荐使用,苹果公司在iOS6之后将这个功能 ...
- 使用node.js进行API自动化回归测试
概述 传统的QA自动化测试通常是基于GUI的,比如使用Selenium,模拟用户在界面上操作.但GUI测试的开发.维护成本和运行的稳定性一直是测试界的老大难问题.投入大量的人力物力开发.维护.运行,却 ...