少说多做,句句都会得到别人的重视;多说少做,句句都会受到别人的忽视。
本讲内容:ActionBar
一、ActionBar介绍
ActionBar是一种新増的导航栏功能,在Android 3.0之后加入到系统的API当中,是一个标识应用程序和用户位置的窗口功能,并且给用户提供操作和导航模式。
1)移除ActionBar的两种方式:
1、将theme指定成Theme.Holo.NoActionBar
2、在Activity中调用以下方法
ActionBar actionBar=getActionBar();
actionBar.hide();
修改Action Bar的图标和标题
<activity
android:name=".MainActivity"
android:label="@string/hello_world"
android:logo="@drawable/pic" >
示例一:
添加Action按钮
ActionBar可以根据应用程序当前的功能来提供与其相关的Action按钮,这些按钮都会以图标或文字的形式直接显示在ActionBar上。如果按钮过多,ActionBar上显示不完,多出的一些按钮可以隐藏在overflow里面(最右边的三个点就是overflow按钮),点击一下overflow按钮就可以看到全部的Action按钮了。当Activity启动的时候,系统会调用Activity的onCreateOptionsMenu()方法来取出所有的Action按钮,我们只需要在这个方法中去加载一个menu资源,并把所有的Action按钮都定义在资源文件里面就可以了。
下面是res/menu/main.xml 文件:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.actionbardemo.MainActivity" >
<item
android:id="@+id/action_edit"
android:icon="@android:drawable/ic_menu_edit"
app:showAsAction="always"
android:title="@string/edit"/>
<item
android:id="@+id/action_delete"
android:icon="@android:drawable/ic_menu_delete"
app:showAsAction="always"
android:title="@string/delete"/>
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
android:icon="@android:drawable/ic_menu_set_as"
app:showAsAction="never"/>
</menu>
其中id是该Action按钮的唯一标识符,icon用于指定该按钮的图标,title用于指定该按钮可能显示的文字(在图标能显示的情况下,通常不会显示文字),如果Action按钮在ActionBar中显示,用户可能通过长按该Action按钮的方式来查看到title的内容。 showAsAction则指定了该按钮显示的位置,主要有以下几种值可选:always表示永远显示在ActionBar中,如果屏幕空间不够则无法显示,ifRoom表示屏幕空间够的情况下显示在ActionBar中,不够的话就显示在overflow中,never则表示永远显示在overflow中。
注意:baritem显示出来
当界面继承ActionBarActivity写app:showAsAction="always"
当界面继承Activity写android:showAsAction="always"
下面是MainActivity.java主界面文件:
public class MainActivity extends ActionBarActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_edit:
Toast.makeText(this, "action_edit", Toast.LENGTH_LONG).show();
break;
case R.id.action_delete:
Toast.makeText(this, "action_delete", Toast.LENGTH_LONG).show();
break;
case R.id.action_settings:
Toast.makeText(this, "action_settings", Toast.LENGTH_LONG).show();
break;
}
return super.onOptionsItemSelected(item);
}
}
示例二:通过Action Bar图标进行导航
启用ActionBar图标导航的功能,可以允许用户根据当前应用的位置来在不同界面之间切换。
系统默认的图标 自己设置的图标
可以看到左上角的图标导航,可以实现返回上一个界面,与Back键不同之处,可以指定返回界面
实现ActionBar导航功能的三个步骤:
步骤一:调用setDisplayHomeAsUpEnabled()方法,并传入true
ActionBar actionBar=getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
步骤二:AndroidManifest.xml中配置父Activity
<activity
android:name=".MainActivity"
android:logo="@drawable/pic" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".LaunchActivity" />
</activity>
这里通过meta-data标签指定了MainActivity的父Activity是LaunchActivity,在Android 4.1版本之后,也可以直接使用android:parentActivityName这个属性来进行指定,如下所示:
<activity
android:name=".MainActivity"
android:label="@string/hello_world"
android:logo="@drawable/pic"
android:parentActivityName=".LaunchActivity" >
步骤三: 对android.R.id.home事件进行一些特殊处理
下面是MainActivity.java主界面文件:
public class MainActivity extends ActionBarActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar=getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
/**
* 其中,调用NavUtils.getParentActivityIntent()方法可以获取到跳转至父Activity的Intent,
* 然后如果父Activity和当前Activity是在同一个Task中的,则直接调用navigateUpTo()方法进行跳转,
* 如果不是在同一个Task中的,则需要借助TaskStackBuilder来创建一个新的Task。
*/
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);
}
break;
}
return super.onOptionsItemSelected(item);
}
}
下面是res/values/styles文件(改变左上角的图标导航)
<style name="MyTheme" parent="AppBaseTheme">
<item name="android:homeAsUpIndicator">@drawable/logo</item>
</style>
下面是AndroidManifest.xml文件
<activity
android:name=".MainActivity"
android:label="@string/hello_world"
android:logo="@drawable/pic"
android:theme="@style/MyTheme"
android:parentActivityName=".LaunchActivity" >
示例三: 添加Action View
ActionView它能在ActionBar直接显示一个具体的视图,如搜索框,而不只是一个Button。 为了声明一个ActionView,我们可以在menu资源中通过actionViewClass属性来指定一个控件,例如可以使用如下方式添加SearchView:
<item
android:id="@+id/action_search"
android:actionViewClass="android.widget.SearchView"
android:icon="@android:drawable/ic_menu_search"
android:showAsAction="ifRoom|collapseActionView"
android:title="@string/action_search"/>
点击这个搜索按钮,这时SearchView就会展开占满整个ActionBar,而其它的Action按钮由于将showAsAction属性设置成了ifRoom,此时都会隐藏到overflow当中。
如果你希望在代码中对SearchView的属性进行配置(比如添加监听事件等),只需要在onCreateOptionsMenu()方法中获取该ActionView的实例就可以了,代码如下所示:
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
return true;
}
示例四:设置Overflow按钮总是显示
系统会默认如果手机没有物理Menu键的话,overflow按钮就可以显示,如果有物理Menu键的话,overflow按钮就不会显示出来。实际上,在ViewConfiguration这个类中有一个叫做sHasPermanentMenuKey的静态变量,系统就是根据这个变量的值来判断手机有没有物理Menu键的。当然这是一个内部变量,我们无法直接访问它,但是可以通过反射的方式修改它的值,让它永远为false就可以了
private void setOverflowShow(){
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()方法中调用setOverflowShow()方法就可以将sHasPermanentMenuKey设置成false了。
示例五:让Overflow中的选项显示图标
系统默认设置隐藏在overflow中的Action按钮只显示文字,不显示图片。实际上是由MenuBuilder这个类的setOptionalIconsVisible方法来决定的,默认 是false,如果我们通过反射在overflow被展开的时候给这个方法传入true,那么里面的每一个Action按钮对应的图标就都会显示出来了。
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被展开的时候就会回调这个方法。
示例六:添加Action Provider
添加一个Action Provider,我们需要在<item>标签中指定一个android:actionProviderClass属性,在里面填入Action Provider的完整类名。我们可以通过继承ActionProvider类的方式来创建一个自己的Action Provider,同时,Android也提供好了几个内置的Action Provider,比如说ShareActionProvider。由于每个Action Provider都可以自由地控制事件响应,所以它们不需要在onOptionsItemSelected()方法中再去监听点击事件,而是应该在onPerformDefaultAction()方法中去执行相应的逻辑。
<item
android:id="@+id/action_share"
android:actionProviderClass="android.widget.ShareActionProvider"
android:icon="@android:drawable/ic_menu_share"
android:showAsAction="ifRoom"
android:title="@string/action_share"/>
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
MenuItem shareItem=menu.findItem(R.id.action_share);
ShareActionProvider provider=(ShareActionProvider) shareItem.getActionProvider();
provider.setShareIntent(getDefaultIntent());
return true;
}
private Intent getDefaultIntent(){
Intent intent=new Intent(Intent.ACTION_SEND);
intent.setType("image/*");
return intent;
}
这里通过Intent来定义出你想分享哪些东西了,我们只需要在onCreateOptionsMenu()中调用MenuItem的getActionProvider()方法来得到该ShareActionProvider对象,再通过setShareIntent()方法去选择构建出什么样的一个Intent就可以了。
示例七:自定义Action Provider
<item
android:id="@+id/action_share"
android:actionProviderClass="com.example.actionbardemo.MyActionProvider"
android:icon="@drawable/ic_launcher"
android:showAsAction="ifRoom"
android:title="@string/action_share"/>
注意导入的不是V4包,否则会报错
package com.example.actionbardemo;
import android.content.Context;
import android.view.ActionProvider;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import android.view.View;
import android.widget.Toast;
/**
* 自定义Action Provider
*/
public class MyActionProvider extends ActionProvider {
public MyActionProvider(Context context) {
super(context);
}
public View onCreateActionView() {
return null;
}
public void onPrepareSubMenu(SubMenu subMenu) {
subMenu.clear();
subMenu.add("sub item1").setIcon(R.drawable.ic_launcher).setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
return true;
}
});
subMenu.add("sub item2").setIcon(R.drawable.ic_launcher).setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
return false;
}
});
}
/**
* 为了表示这个Action Provider是有子菜单的,需要重写hasSubMenu()方法并返回true,
* 然后在onPrepareSubMenu通过调用SubMenu的add()方法添加子菜单。
*/
public boolean hasSubMenu() {
return true;
}
}
示例八:使用主题
Android中有两个最基本的Activity主题可以用于指定ActionBar的颜色,分别是:
Theme.Holo,这是一个深色系的主题。
Theme.Holo.Light,这是一个浅色系的主题。
你可以将这些主题应用到你的整个应用程序,也可以只应用于某个Activity。通过在AndroidManifest.xml文件中给<application>或<activity>标签指定android:theme属性就可以实现了。比如:
<application android:theme="@android:style/Theme.Holo.Light"/>
例九: 自定义背景
1)修改ActionBar的背景,我们可以通过创建一个自定义主题并重写actionBarStyle属性来实现。这个属性可以指向另外一个样式,然后我们在这个样式中重写background这个属性就可以指定一个drawable资源或颜色,从而实现自定义背景的功能。
下面是res/values/styles.xml文件
<style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light">
<item name="android:actionBarStyle">@style/MyActionBar</item>
</style>
<style name="MyActionBar" parent="@android:style/Widget.Holo.Light.ActionBar">
<item name="android:background">#f4842d</item>
</style>
<application android:theme="@style/CustomActionBarTheme" >
定义一个CustomActionBarTheme主题,并让它继承自Theme.Holo.Light。然后在其内部重写了actionBarStyle这个属性,然后将这个属性指向了MyActionBar这个样式,我们在这个样式中又重写了background属性,并给它指定了一个背景色。效果如下图所示:
2)自定义文字颜色:将文字颜色改成白色。
下面是res/values/styles.xml文件
<style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light">
<item name="android:actionBarStyle">@style/MyActionBar</item>
</style>
<style name="MyActionBar" parent="@android:style/Widget.Holo.ActionBar">
<item name="android:background">#f4842d</item>
<item name="android:titleTextStyle">@style/MyActionBarTitleText</item>
</style>
<style name="MyActionBarTitleText" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Title">
<item name="android:textColor">#fff</item>
<item name="android:textSize">17sp</item>
</style>
<application android:theme="@style/CustomActionBarTheme" >
Take your time and enjoy it