ActionBar是在Android3.0(API11)之后引入的。在API11以下,Android提供了 android.support.v7.app.ActionBar包支持,API11以上,使用android.app.ActionBar使用ActionBar。
一,ActionBar的组成:
2.View Control 下拉菜单,用于切换下方页面,也可以只是显示标题
3.Action buttons 一般是比较重要的操作按钮放在这个区域
4.Action overflow 其他操作
二,添加/隐藏 ActionBar
使用 support library,给应用添加ActionBar的方法:
1.Activity继承 ActionBarActivity.
2.使用 Theme.AppCompat 开头的主题
<activity android:theme="@style/Theme.AppCompat.Light" ... >
在API11及以上,可以使用 Theme.Holo主题及它的子主题。
如果需要隐藏ActionBar。
API11以下:
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
API11及以上:
在清单文件中去掉:
android:theme="@android:style/Theme.Holo.NoActionBar"
在代码中去掉:
ActionBar actionBar = getActionBar();
actionBar.hide();
代码去掉ActionBar的代码要写在Activity 的onCreate的 setContentView语句前面。
三.App Icon:
ActionBar左侧的图片默认和清单文件的<application>标签下的 android:icon指定的图片一致。如果需要更改,可以在<application>下加上 android:icon,
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
uiOptions="splitActionBarWhenNarrow"
android:logo="@drawable/cx"
android:theme="@style/AppTheme" >
四.Action Items:
显示在Action Bar上的Action Button和隐藏在Action overflow中的项都属于Action Item
当Activity启动时,会调用onCreateOptionsMenu()生成action item,每一个action item是在菜单的资源文件中声明的。
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.learnactionbar.MainActivity" >
<item android:id="@+id/action_search"
android:icon="@drawable/ic_action_search"
android:title="搜索"/>
<item android:id="@+id/action_copy"
android:icon="@drawable/ic_action_copy"
android:title="复制"/>
</menu>
在onCreateOptionsMenu中启用这个菜单:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
默认的Action Item是放在Action overflow中的,如果需要作为一个Action Button,显示地显示在Action Bar上,则需要在 <item>标签中加上showAsAction="ifRoom"
<item android:id="@+id/action_search"
android:icon="@drawable/ic_action_search"
android:showAsAction="ifRoom"
android:title="搜索"/>
指定了title属性后,当Action Item作为Action Button显示时,长按图标会在图标下面弹出Title。在同时指定了icon和title的情况下,往往只显示icon。
除了ifRoom以外,还可以指定值为always。指定了这个值后,Action Item总是显示为Action Button.
当点击Action Item时,onOptionsItemSelected()被回调,MenuItem作为参数,由于在<item>中指定了id,可以通过item.getItemId()判断哪个被点击。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_search:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Action Bar的menu文件可以在Fragment的方法中inflate
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.main, menu);
}
同时需要在Fragment的onCreate方法中加上这句:
setHasOptionsMenu(true);
这样一来,当Fragment随Activity启用之后,会先调用Activity的
onCreateOptionsMenu,再调用Fragment的onCreateOptionsMenu,点击Action Item后,会先调用Activity的onOptionsItemSelected,再调用Fragment的onOptionsItemSelected。
五.ActionView:
API3.0以下可以在菜单xml中这样声明ActionView:
<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.learnactionbar2.MainActivity" >
<item
android:id="@+id/action_tv"
android:orderInCategory="100"
android:title="item1"
android:icon="@drawable/ic_action_search"
app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="android.widget.TextView"
/>
</menu>
app:actionViewClass属性指定了需要在ActionBar上显示的view。collapseActionView属性指定了,ActionView被折叠到Action Button中。
如果需要在代码中对ActionView进行设置,可以在onCreateOptionsMenu中获取它:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
MenuItem textItem = menu.findItem(R.id.action_tv);
TextView tv = (TextView) MenuItemCompat.getActionView(textItem);
tv.setText("文字");
return true;
}
初始界面:
点击放大镜后的效果:
在API11及以上的版本,在xml中,将app:这样的自定义命名空间改为android:,并且在onCreateOptionsMenu中,这样获取:
TextView tv = (TextView) menu.findItem(R.id.action_tv).getActionView();
显示在 tv.setText("文字");
ActionView显示在ActionBar上面时,点击手机的虚拟返回键或者左边的“up”键都可以收起ActionView。
监听ActionView的显示和折叠,API11以下:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
MenuItem textItem = menu.findItem(R.id.action_tv);
TextView tv = (TextView) MenuItemCompat.getActionView(textItem);
tv.setText("文字");
MenuItemCompat.setOnActionExpandListener(textItem, new OnActionExpandListener() {
@Override
public boolean onMenuItemActionCollapse(MenuItem arg0) {
Log.v("TEST", "!!onMenuItemActionCollapse!!");
return true;
}
@Override
public boolean onMenuItemActionExpand(MenuItem arg0) {
Log.v("TEST", "!!onMenuItemActionExpand!!");
return true;
}
});
return true;
}
API11以上:
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.main, menu);
TextView tv = (TextView) menu.findItem(R.id.action_tv).getActionView();
tv.setText("文字");
MenuItem m = menu.findItem(R.id.action_tv);
m.setOnActionExpandListener(new OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
Log.v("TEST", "!!onMenuItemActionExpand!!");
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
Log.v("TEST", "!!onMenuItemActionCollapse!!");
return true;
}
});
}
六.Action Provider
Action Provider和Action Button的位置一样,当点击它时,可以显示子菜单。
声明 action provider:在menu的<item> 中添加actionProviderClass属性。以分享按钮ShareActionProvider为例:
<item android:id="@+id/action_share"
android:title="share"
android:showAsAction="ifRoom"
android:actionProviderClass="android.widget.ShareActionProvider"
/>
在ActionBar上显示分享按钮后,为其加上分享的方式:
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.main, menu);
MenuItem shareItem = menu.findItem(R.id.action_share);
mShareActionProvider = (ShareActionProvider) shareItem.getActionProvider();
mShareActionProvider.setShareIntent(getDefaultIntent());
}
private Intent getDefaultIntent() {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/*");
return intent;
}
七.Navigation Tab:
ActionBar上的Tab会根据屏幕大小自适应,在平板这样的宽屏设备上时,Tab会显示在ActionBar上,手机这样的窄屏时,会显示在ActionBar下方。
宽屏:
窄屏:
实现步骤如下:
1.设置NavigationMode为 ActionBar.NAVIGATION_MODE_TABS
2.新建Tab,为Tab添加标题,TabListener
3.为ActionBar添加Tab
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Notice that setContentView() is not used, because we use the root
// android.R.id.content as the container for each fragment
// setup action bar for tabs
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(false);
Tab tab = actionBar.newTab()
.setText(R.string.artist)
.setTabListener(new TabListener<ArtistFragment>(
this, "artist", ArtistFragment.class));
actionBar.addTab(tab);
tab = actionBar.newTab()
.setText(R.string.album)
.setTabListener(new TabListener<AlbumFragment>(
this, "album", AlbumFragment.class));
actionBar.addTab(tab);
}
TabListener代码:
public static class TabListener<T extends Fragment> implements ActionBar.TabListener {
private Fragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
/** Constructor used each time a new tab is created.
* @param activity The host Activity, used to instantiate the fragment
* @param tag The identifier tag for the fragment
* @param clz The fragment's Class, used to instantiate the fragment
*/
public TabListener(Activity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
/* The following are each of the ActionBar.TabListener callbacks */
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// Check if the fragment is already initialized
if (mFragment == null) {
// If not, instantiate and add it to the activity
mFragment = Fragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content, mFragment, mTag);
} else {
// If it exists, simply attach it in order to show it
ft.attach(mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
ft.detach(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// User selected the already selected tab. Usually do nothing.
}
}
TabListener接收Fragment的 Class<T> clz对象作为构造参数,用于在Tab被选中和反选时,通过FragmentTransaction切换。注意这里不需要手动调用FragmentTransaction的commit,系统会自动调用。要获取当前选择的Tab,可以调用 getSelectedNavigationIndex();
八.下拉导航
下拉导航在ActionBar上提供一个Spinner,用于切换视图。
实现下拉导航的步骤:
1.创建一个提供下拉布局内容的SpinnerAdapter
2.实现 ActionBar.OnNavigationListener接口,用户选中下拉列表中item时的行为在这个接口的实现类中定义
3.在Activity的onCreate方法中,设置ActionBar的NavigationMode为NAVIGATION_MODE_LIST
4.通过 setListNavigationCallbacks(),传入adapter和callback参数,设置下拉列表的回调
示例:
public class MainActivity extends Activity {
String[] mStrings;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
mStrings = getResources().getStringArray(R.array.action_list);
SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this,
R.array.action_list,
android.R.layout.simple_spinner_dropdown_item);
getActionBar().setDisplayShowTitleEnabled(false);
getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
getActionBar().setListNavigationCallbacks(mSpinnerAdapter,
mOnNavigationListener);
}
OnNavigationListener mOnNavigationListener = new OnNavigationListener() {
@Override
public boolean onNavigationItemSelected(int position, long itemId) {
ListContentFragment newFragment = new ListContentFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(android.R.id.content, newFragment, mStrings[position]);
ft.commit();
return true;
}
};
public class ListContentFragment extends Fragment {
private String mText;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mText = getTag();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView text = new TextView(getActivity());
text.setText(mText);
return text;
}
}
}
九.ActionBar的样式
可以在styles.xml中自定义ActionBar的样式。
<resources>
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:actionBarStyle">@style/MyActionBar</item>
</style>
<style name="MyActionBar" parent="@style/Widget.AppCompat.ActionBar">
<item name="android:titleTextStyle">@style/TitleTextStyle</item>
<item name="android:background">@color/purple</item>
<!-- Support library -->
<item name="titleTextStyle">@style/TitleTextStyle</item>
<item name="background">@color/purple</item>
</style>
<style name="TitleTextStyle" parent="@style/TextAppearance.AppCompat.Widget.ActionBar.Title">
<item name="android:textColor">@android:color/holo_green_light</item>
</style>
</resources>
上面把ActionBar上的Text字体颜色定义成了浅绿色,ActionBar背景色定义成了紫色。
十.ActionMode
有些App实现了这种效果:当对界面上的某个地方长按后,ActionBar上出现一系列的复制/转发等按钮。这种效果是通过ActionMode来实现的。
使用ActionMode的步骤:
1.实现ActionMode.Callback接口
2.为view的长按/点击等事件通过 startActionMode()设置ActionMode
public class MainActivity extends ActionBarActivity {
private ActionMode mActionMode;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
tv.setOnClickListener(new OnShowActionMode());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_tv) {
return true;
}
return super.onOptionsItemSelected(item);
}
private class OnShowActionMode implements OnClickListener {
@Override
public void onClick(View v) {
mActionMode = startActionMode(mActionModeCallback);
mActionMode.setTitle("action mode");
}
}
ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.menu_action_mode, menu);
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (item.getItemId() == R.id.action_copy) {
Toast.makeText(MainActivity.this, "!!!", Toast.LENGTH_SHORT).show();
}
return true;
}
};
}
menu_action_mode.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.learnactionbar2.MainActivity" >
<item
android:id="@+id/action_copy"
android:icon="@drawable/ic_action_copy"
android:orderInCategory="100"
android:title="overflow_item"
app:showAsAction="ifRoom"/>
</menu>