android ActionBar小结

来源:互联网 发布:Cint在VB中是什么意思 编辑:程序博客网 时间:2024/06/06 11:31

前言:最近遇到ActionBar,之前没有研究过,所以就做了一下总结。网上碰到了几个博文挺好的,就保存了。


1、什么是Action Bar
Action Bar被认为是新版Android系统中最重要的交互元素,在程序运行中一直置于顶部,主要起到的作用在于:
1)突出显示一些重要操作(如“最新”、“搜索”等)
2)在程序中保持统一的页面导航和切换方式
3)将使用频率低的功能放在Action overflow中,节省页面空间
4)一个固定区域显示程序标示


2、Action Bar分成四个区域
AppIcon:可显示软件icon,也可用其他图标代替。当软件不在最高级页面时,图标左侧会显示一个左箭头,用户可以通过这个箭头向上导航。
视图切换:如果你的应用要在不同的View中显示数据,这部分允许用户来切换View。一般的作法是用一个drop-down菜单或者是TabControls。如果只有一个界面,那这里可以显示App Title或者更长点的商标信息
Action Buttons:这个放最重要的软件功能,放不下的按钮就自动进入Action overflow了。
Action overflow:把不常用的Actions移到Action overflow

                                                                     图 1

通过设置ActionBar的serDisplayShowHomeEanbled(false)和setDisplayShowTitleEanbled(fasle)禁用操作栏的图标和标题;


3. 添加ActionBar

从Android3.0(API级别 11)开始,Action bar被包含在所有的使用Theme.Hole主题的Activity(或者是这些Activity的子类)中,当targetSdkVersion或minSdkVersion属性被设置为“11”或更大的数值是,这个主题是默认的主题一。如:

<manifest ... >      <uses-sdk android:minSdkVersion="4"                android:targetSdkVersion="11" />      ...  </manifest>
在这个例子中,应用程序要求最小的API版本级别是4(Android 1.6),但是它还要求了目标API版本级别是11(Android 3.0)。这样,当应用程序运行在Android3.0或更高的版本上时,系统就会给每个Activity应用holographic  主题,这样,每个Activity就会包含Action bar。
 如果你想使用ActionBar API来进行添加导航模式和修改操作栏样式的操作,你应该把minSdkVersion属性设置为“11”或更大的值。有一些方法可以使你的应用支持更旧的Android版本,同时在API等级为11或更高的API等级的机器的使你的应用支持一些Action bar apis。

4. 删除ActionBar

如果你不想要Action bar,把Activity的主题设置为Theme.Holo.NoActionBar就可以了,如:

<activity android:theme="@android:style/Theme.Holo.NoActionBar">
或者使用Action bar的 hide()方法,如下:
ActionBar actionBar = getActionBar();  actionBar.hide();

当Action bar隐藏时,系统会调整你的Activity来填充当前有效的屏幕空间。你能够使用show()方法来再次显示操作栏。

在隐藏和删除Action bar时,要当心为了适应被Action bar占用的空间而导致的Activity的重新布局。如果你的Activity有规律的隐藏和显示Action bar,你可能想要使用覆盖模式。覆盖模式在Activity的顶部描画操作栏,而不是在它们所拥有的屏幕的区域。这样,在Action bar隐藏和重新显示时,你的布局保持不变。要使用覆盖模式,就要给Activity创建一个主题,并且把android:windowActionBarOverlay属性设置为true。


5. 添加操作项

用户可以通过菜单栏中的操作项直接访问所需资源,操作项能够包含一个图标或文本标题。如果一个菜单项不能作为一个操作项显示,那么系统就会把它放到溢出菜单中。用户可以通过点击溢出菜单按钮显示其余的菜单。
可以这么理解,Action Item其实就是之前的旧版本中的MenuItem,只不过把它整合到ActionBar中了。所以,当Activity首次启动时,系统会调用onCreateOptionsMenu()方法给Activity的ActionBar添加操作栏和溢出菜单。

    @Override    public boolean onCreateOptionsMenu(Menu menu) {        Log.d(TAG, "====onCreateOptionsMenu=====");                MenuItem add = menu.add(0, 1, 0, "add");        MenuItem delete = menu.add(0, 2, 1, "delete");        add.setIcon(R.drawable.add);        add.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);        delete.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);                return super.onCreateOptionsMenu(menu);    }

我们知道,菜单项是有图标和文本标题的,在代码中,通过setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)请求把一个菜单项作为一个操作项来显示。用这种方式,只有在有效的空间时,菜单项才能显示在操作栏中。如果没有足够的空间,这个菜单项会显示在溢出菜单中。

如果你的菜单项支持标题和图标,那么默认情况下,操作项仅显示图标。如果你要显示文本标题,就要添加如下属

性:setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM|MenuItem.SHOW_AS_ACTION_WITH_TEXT);

注:MenuItem.SHOW_AS_ACTION_WITH_TEXT值示意操作栏要显示文本标题。操作栏会尽可能的显示这个标题,但是,如果图标有效并且受到操作栏空间的限制,文本标题有可能显示不全。

当然也可以用记载资源的方式,如:

    @Override    public boolean onCreateOptionsMenu(Menu menu) {        Log.d(TAG, "====onCreateOptionsMenu=====");        getMenuInflater().inflate(R.menu.action, menu);        SearchView search = (SearchView)menu.findItem(R.id.search).getActionView();                mActionProvider = (ShareActionProvider)menu.findItem(R.id.share).getActionProvider();        mActionProvider.setShareHistoryFileName("share_history.xml");        mActionProvider.setShareIntent(createShareIntent());        return super.onCreateOptionsMenu(menu);    }

资源文件 如下:

<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android">    <item          android:id="@+id/search"          android:actionViewClass="android.widget.SearchView"          android:showAsAction="ifRoom|withText"          android:title="@string/title_search"/>         <item         android:id="@+id/share"        android:title="@string/title_share"        android:showAsAction="ifRoom"        android:actionProviderClass="android.widget.ShareActionProvider"/>        <item         android:id="@+id/test"        android:title="@string/title_test"        android:showAsAction="ifRoom" >        <!--menu>            <item                 android:id="@+id/test_1"                android:title="test_1"                android:showAsAction="ifRoom" />                        <item                 android:id="@+id/test_2"                android:title="title_2"                android:showAsAction="never"/>"        </menu-->    </item>        <item         android:id="@+id/test_3"        android:title="test_3"        android:showAsAction="ifRoom" />        <item         android:id="@+id/test_4"        android:title="test_4"        android:showAsAction="ifRoom" />        <item         android:id="@+id/test_5"        android:title="test_5"        android:showAsAction="ifRoom" />        <item         android:id="@+id/test_6"        android:title="test_6"        android:showAsAction="ifRoom" /></menu>
其中属性android:showAsAction="ifRoom"跟code中的setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)是相同的作用。

 showAsAction属性共有五个值:ifRoom、never、always、withText、collapseActionView,可以混合使用。

ifRoom
会显示在Item中,但是如果已经有4个或者4个以上的Item时会隐藏在溢出列表中。当然个
数并不仅仅局限于4个,依据屏幕的宽窄而定
never永远不会显示。只会在溢出列表中显示,而且只显示标题,所以在定义item的时候,最好
把标题都带上。
always无论是否溢出,总会显示。withTextwithText值示意Action bar要显示文本标题。Action bar会尽可能的显示这个
标题,但是,如果图标有效并且受到Action bar空间的限制,文本标题有可
能显示不全。
collapseActionView 
声明了这个操作视窗应该被折叠到一个按钮中,当用户选择这个按钮时,这个操作视窗展开。否则,
这个操作视窗在默认的情况下是可见的,并且即便在用于不适用的时候,也要占据操作栏的有效空间。
一般要配合ifRoom一起使用才会有效果。

                                                                                      表 1

可以看到资源文件中最后面的几个test的item,虽然设置属性为ifRoom,但是在空间不够的情况下,只能显示在溢出菜单中。


给每个菜单项定义android:title属性是至关重要的,即使你没有给操作项声明标题,原因如下:
a)  如果操作栏中没有足够的空间来显示操作项,那么菜单项就会显示在溢出菜单中,并仅显示标题
b) 屏幕阅读器要给视障用户朗读菜单项标题;
c)  如果仅用图标来显示操作项,那么,用户能够长按这个项目,用操作项的标题来显示提示信息。


选择操作项:
通过评估一些关键的特性,你应该仔细的选择选项菜单中的那些菜单项应该作为操作项来显示,通常,每个操作项应该至少满足下列特性之一:
a) 经常使用:用户百分之七十以上的访问都需要使用的操作,或者是要连续的多次使用的操作。
b) 重要:它是一个用户能够很容易找到的操作,即使它不是经常性的操作,也需要用户在需要的时候能够轻易的找到它,并执行。
如,Wi-Fi设置中的添加网络等。
c) 典型:它是一些类似应用程序的操作栏中提供的典型操作,因此,用户都期望在操作栏中能够找到它。
如,电子邮件或社交应用程序中的“刷新”操作。

如果你想要把四个以上的菜单项调整为操作项,那么你就应该认真考虑一下他们相对的重要性级别,并且尝试不要超过四个以上的操作项设置(并且还有使用“ifRoom”属性值的设置,允许系统在遇到空间受限的比较小的屏幕的时候,能够把靠后的操作项放到悬浮菜单中)。即使在一些宽屏设备上,空间充足,你也不应该创建很多操作项,这样会扰乱UI的布局,而且更像一个桌面工具栏,因此要保持最小数量的操作项。
另外,以下操作应该永远不要作为操作项来显示:设置、帮助、意见反馈、或类似的操作。要把它们始终保留在悬浮菜单中。
注意:不是所有的设备都给检索提供了专有的硬件按钮,因此,如果是你应用程序中的一个重要功能,它应该始终作为一个操作项来显示(而且通常要把放到第一项的位置,尤其是操作窗口中提供这个操作的时候)。


6. 使用分离式操作栏

当你的应用程序正在Android4.0(API 级别 14)或以上的版本上运行,那么还有一种叫做“分隔操作栏”的额外模式对action bar有效。当你启用分隔操作栏模式时,在屏幕的底部会显示一个独立的横条,用于显示Activity在窄屏设备(如竖屏手机)上运行时的所有操作项。

把action bar分隔成独立的操作项,确保在窄屏设备上有合适的空间来显示所有的操作项,同时把导航条和标题元素留在顶部。
要启用分离式操作栏,只需简单的在<application>或<activity>元素中添加uiOptions=”splitActionBarWhenNarrow”属性设置就可以了。如程序:

<activity    android:name="com.shift.actionbar.MyActionBar"    android:uiOptions="splitActionBarWhenNarrow"    android:label="@string/app_name" >

要注意,Android会基于当前屏幕的尺寸用各种方式来调整操作栏的外观。使用分离式操作栏只是你能够启用的允许操作栏针对不同屏幕尺寸来进一步优化用户体验的选项之一。你还可以允许操作栏把导航选项标签折叠到主操作栏中,如果你在操作栏中使用导航选项标签,那么一旦操作项在窄屏设备上被分离,这些导航选项标签就可能填充到主操作栏中,而不是被分离到堆叠起来的操作栏。尤其是如果你禁用了操作栏的图标和标题(用setDisplayShowHomeEnabled(false)和setDisplayShowTitleEnabled(false)方法),那么导航选项标签就会折叠到主操作栏中。


                                             图 2

7. 使用应用程序图标导航

默认情况下,应用程序图标显示在操作栏的左边。你能够把这个图标当做操作项来使用。应用程序应该在这个图标上响应以下两个操作之一:
a)  返回应用程序的“主”Activity;
b)  向应用程序上级页面导航。
当用户触摸这个图标时,系统会调用Activity带有android.R.id.home ID的onOptionsItemSelected()方法。在这个响应中,你既可以启动主Activity,也可以返回你的应用程序结构化层次中用户上一步操作的界面。
如果你要通过应用程序图标的响应来返回主Activity,那么就应该在Itent对象中包括FLAG_ACTIVITY_CLEAR_TOP标识。用这个标记,如果你要启动的Activity在当前任务中已经存在,那么,堆栈中这个Activity之上的所有的Activity都有被销毁,并且把这个Activity显示给用户。添加这个标识往往是重要的,因为返回主Activity相当与一个回退的动作,因此通常不应该再创建一个新的主Activity的实例,否则,最终可能会在当前任务中产生一个很长的拥有多个主Activity的堆栈。


例如,下例的onOptionsItemSelected()方法实现了返回应用程序的主Activity的操作:

    @Override    public boolean onOptionsItemSelected(MenuItem item) {        switch (item.getItemId()) {        case android.R.id.home:            // app icon in action bar clicked; go home            Intent intent = new Intent(this, MyActionBar.class);            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);              startActivity(intent);              return true;          default:              return super.onOptionsItemSelected(item);                  }    }
在用户从另一个应用程序进入当前Activity的情况下,你可能还想要添加FLAG_ACTIVITY_NEW_TASK标识。这个标识确保在用户返回主页或上级页面时,新的Activity不会被添加到当前的任务中,而是在属于你自己的应用程序的任务中启动。例如,如果用户通过被另一个应用程序调用的Intent对象启动了你的应用程序中的一个Activity,那么选择操作栏图标来返回主页或上级页面时,FLAG_ACTIVITY_CLEAR_TOP标识会在属于你的应用程序的任务中启动这个Activity(不是当前任务)。系统既可以用这个新的Activity做根Activity来启动一个新的任务,也可以把存在后台的拥有这个Activity实例的一个既存任务带到前台来,并且目标Activity会接受onNewIntent()回调。因此,如果你的Activity要接收另一个应用程序的Intent对象,那么通常应该给这个Intent对象添加FLAG_ACTIVITY_NEW_TASK标识,如:
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
注意:如果你要使用应用图标来返回主页,要注意从Android4.0(API 级别 14)开始,必须通过调用setHomeButtonEnabled(true)方法确保这个图标能够作为一个操作项(在以前的版本,默认情况下,这个图标就能够作为一个操作项)

要使应用程序图标能够向上导航,就要在ActionBar中调用setDisplayHomeAsUpEnabled(true)方法。


8. 添加操作视窗

1) 可以添加一个视图作为一个Action Item。通过在xml元素的android:actionLayout属性制定我们希望现实布局资源的ID(例如@layout/mysearchview)

2) 也可以选择添加android:actionViewClass属性(menus.xml文件中<item>的属性)分配与完全限定的类名描述我们想要显示的视图(例如android:actionViewClass=”android.widget.SearchView”)

  android.widget.SearchView是系统内置的搜索框视图,效果图如下

                                          图 3

    上图为折叠和展开的搜索视窗的操作栏

通过给android:showAsAction属性添加“collapseActionView”属性值,能够让操作视窗可以折叠起来。如果需要,同时也可以在代码中通过expandActionView()collapseActionView()方法来展开或折叠操作视窗。


9. 添加导航选项标签(tab选项)

当你想要在一个Activity中提供导航选择标签时,使用操作栏的选项标签是一个非常好的选择(而不是使用TabWidget类),因为系统会调整操作栏选项标签来适应不同尺寸的屏幕的需要---在屏幕足够宽的时候,导航选项标签会被放到主操作栏中(如图4);当屏幕太窄的时候,选项标签会被放到一个分离的横条中(如图5)

                           图 4

              图 5

要使用选项标签在Fragmengt之间切换,你必须在每次选择一个选项标签时执行一个Fragment事务。如果你不熟悉如何使用  FragmentTransaction对象来改变Fragment,请阅读Fragment开发指南。

首先,你的布局必须包含一个用于放置跟每个Fragment对象关联的选项标签的ViewGroup对象。并且要确保这个ViewGroup对象有一个资源ID,以便你能够在选项标签的切换代码中能够引用它。另外,如果选项标签的内容填充在Activity的布局中(不包括操作栏),那么Activity不需要任何布局(你甚至不需要调用setContentView()方法)。相反,你能够把每个Fragment对象放到默认的根ViewGroup对象中,你能够用android.R.id.content ID来引用这个ViewGroup对象(在Fragment执行事务期间,你能够在下面的示例代码中看到如何使用这个ID的。
决定了Fragment对象在布局中的显示位置后,添加选项标签的基本过程如下:
a) 实现ActionBar.TabListener接口。这个接口中回调方法会响应选项标签上的用户事件,以便你能够切换Fragment对象;
b) 对于每个要添加的选项标签,都要实例化一个ActionBar.Tab对象,并且调用setTabListener()方法设置ActionBar.Tab对象的事件监听器。还可以用setText()或setIcon()方法来设置选项标签的标题或图标。
c) 通过调用addTab()方法,把每个选项标签添加到操作栏。

在查看ActionBar.TabListener接口时,注意到回调方法只提供了被选择的ActionBar.Tab对象和执行Fragment对象事务的FragmentTransaction对象---没有说明任何有关Fragment切换的事。因此。你必须定义自己的每个ActionBar.Tab之间的关联,以及ActionBar.Tab所代表的适合的Fragment对象(为了执行合适的Fragment事务)。依赖你的设计,会有几种不同的方法来定义这种关联。在下面的例子中,ActionBar.TabListener接口的实现提供了一个构造器,这样每个新的选项标签都会使用它自己的监听器实例。每个监听器实例都定义了几个在对应Fragment对象上执行事务时必须的几个成员变量。

例如,以下示例是ActionBar.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.      }  }

  警告:针对每个回调中的Fragment事务,你都不必调用commit()方法---系统会调用这个方法,并且如果你自己调用了这个方法,有可能会抛出一个异常。你也不能把这些Fragment事务添加到回退堆栈中。

在这个例子中,当对应的选项标签被选择时,监听器只是简单的把一个Fragment对象附加(attach()方法)到Activity布局上---或者,如果没有实例化,就会创建这个Fragment对象,并且把它添加(add()方法)到布局中(android.R.id.content ViewGroup的一个子类),当这个选项标签解除选择时,对应的Fragment对象也会被解除与布局的依附关系。

       ActionBar.TabListener的实现做了大量的工作,剩下的事情就是创建每个ActionBar.Tab对象并把它添加到ActionBar对象中,另外,你必须调用setNavigationMode(NAVIGATION_MODE_TABS)方法来让选项标签可见。如果选项标签的标题实际指示了当前的View对象,你也可以通过调用setDisplayShowTitleEnabled(false)方法来禁用Activity的标题。

 例如,下面的代码使用上面定义的监听器在操作栏中添加了两个选项标签。

@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 = getActionBar();      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);  }
 如果Activity终止了,那么你应该保存当前选择的选项标签的状态,以便当用户再次返回时,你能够打开合适的选项标签。在保存状态的时刻,你能够用getSelectedNavigationIndex()方法查询当前的被选择的选项标签。这个方法返回被选择的选项标签的索引位置。

警告:保存每个Fragment所必须的状态是至关重要的,因为当用户用选项标签在Fragment对象间切换时,它会查看Fragment在离开时样子。
注意:在某些情况下,Android系统会把操作栏选项标签作为一个下拉列表来显示,以便确保操作栏的最优化显示。



参考:

http://blog.csdn.net/yuxlong2010/article/details/9299507

http://blog.csdn.net/xyz_lmn/article/details/8132420







0 0
原创粉丝点击