ActionBar是在Android3.0(API11)之后引入的。在API11以下,Android提供了 android.support.v7.app.ActionBar包支持,API11以上,使用android.app.ActionBar使用ActionBar。
一,ActionBar的组成:
1.App Icon 如果当前不是主页,前面可以加个返回箭头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>
@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>