android 之 ActionBar

一  前言

Action bar就是替换3.0以前的tittle barmenu


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

Action overflow:把不常用的Actions移到Action overflow

二 主题

从3.0开始,Android默认已经启用了ActionBar,使用Android主题(Theme)

Android包含了两种基准的主题,这决定了action bar的颜色:

    - Theme.Holo  深色("dark" )主题。
    - Theme.Holo.Light 浅色( "light" )主题。

你可以通过在<application> 元素下声明android:theme来将主题应用到整个应用中,也可以通过在单独的<activity>元素上声明android:theme将主题应用在一个单独的Activity上。

例如:

<applicationandroid:theme="@android:style/Theme.Holo.Light" ... />

你也可以通过声明Theme.Holo.Light.DarkActionBar 主题让你的action bar为深色,但其余部分都为浅色。.

当在使用Support Library时,你必须使用Theme.AppCompat 主题作为代替:

    - Theme.AppCompat 代表深色( "dark" )主题。theme.
    - Theme.AppCompat.Light 代表浅色("light" )主题。
    - Theme.AppCompat.Light.DarkActionBar 代表带有深色action bar的浅色主题。

确保你在action bar上使用的icon的颜色与你的主题合适。为了帮助你,这里(Action Bar Icon Pack)有浅色和深色action bar对应的合适的action icons。

三  显示和隐藏ActionBar

    1. 把主题设置Application或Activity的主题设置为:
android:theme="@android:style/Theme.Holo.NoActionBar"则会隐藏ActionBar
android studio隐藏ActionBar: 
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
    2. 但是在实际项目中,推荐使用代码控制ActionBar的显示和隐藏。

         ActionBar bar = getActionBar(); //获得ActionBar对象

         bar.show(); //显示ActionBar

         bar.hide(); //隐藏ActionBar

四 给ActionBar增加动作项

  1 加载在XML文件中定义的菜单项资源

    @Override  

    public boolean onCreateOptionsMenu(Menu menu) {  
        MenuInflater inflater = getMenuInflater();  
        inflater.inflate(R.menu.main_activity, menu);  
        return true;  
    }  

       在菜单资源的xml文件中,你能够通过给<item>元素声明android:showAsAction=”ifRoom”属性,请求把一个菜单项作为一个操作项来显示。用这种方式,只在有有效的空间时,菜单项才能显示在Action bar中。如果没有足够的空间,这个菜单项会显示在悬浮菜单中。

        如果你的菜单项支持标题和图标即带有android:title和android:icon属性---那么默认情况下,操作项仅显示图标。如果你要显示文本标题,就要给android:showAsAction属性添加withText设置,如:

  android:icon="@drawable/ic_menu_save"  

  android:title="@string/menu_save"  

  android:showAsAction="ifRoom|withText"

注意: 

  1. withText值示意Action bar要显示文本标题。Action bar会尽可能的显示这个标题,但是,如果图标有效并且受到Action bar空间的限制,文本标题有可能显示不全。
  2. 每个菜单项尽量都设置title属性。如果ActionBar没有空间显示操操作项的时候,则会把这item放入到悬浮菜单中,并仅显示标题。
  3. android:showAsAction的值尽量不要选择always,太多的操作项会创建一个混乱的UI,并且会导致窄屏设备上的布局问题。用ifRoom是个比较好的选择。

     当用户选择了一个操作项时,Activity会接收一个onOptionsItemSelected()的回调,要把android:id属性支持的ID传递给这个方法。可以在这个方法内部对来响应每个具体的操作项。

注意:

     如果该Activity有托管Fragment,则Fragment也可以向ActionBar中添加操作项,添加方式同上。但是必须在Fragment中onActivityCreated()方法中调用setHasOptionsMenu(true);  通知Activity我有菜单要添加。

添加到Fragment中代码块如下:

public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setHasOptionsMenu(true);//通知Activity,当前Fragment也有菜单
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(android.R.layout.simple_spinner_dropdown_item, container, false);
        return view;
    }
    /**
     * Fragment也可以有自己的菜单,但是需要Activity来帮助加载
     */
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        Log.e("MyFragment", "onCreateOptionsMenu....");
        inflater.inflate(R.menu.fragment_menu, menu);
    }
    /**
     * 线执行Activity中的onOptionsItemSelected,然后再执行Fragment中的方法。
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Toast.makeText(getActivity(), "Fragemtn的菜单被执行", 0).show();
        return super.onOptionsItemSelected(item);
    }
先执行Activity中的onOptionsItemSelected再执行Fragment中的onOptionsItemSelected。

2  往ActionBar添加SearchView代码块如下:

XML中添加搜索按钮:

     <item
        android:id="@+id/search"
        android:icon="@android:drawable/ic_search_category_default"
        android:showAsAction="always|collapseActionView"
         android:actionViewClass="android.widget.SearchView"
        android:title="搜索"/>
设置监听:
public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_manu, menu);
        MenuItem item = menu.findItem(R.id.search);  //根据MenuItem的id找到指定的MenuItem
        //找到这个Item中的ActionView
        searchView.setOnQueryTextListener(new OnQueryTextListener() {  //给SearchView设置搜索的监听器
            @Override
            public boolean onQueryTextSubmit(String query) {
                Toast.makeText(MainActivity.this, "开始搜索.....", 0).show();
                return false;
            }
            @Override
            public boolean onQueryTextChange(String newText) {
                return false;
            }
        });
        return super.onCreateOptionsMenu(menu);
}

五  使用分离式操作栏

只需简单的在<application><activity>元素中添加uiOptions=”splitActionBarWhenNarrow”属性设置就可以了。

android:uiOptions="splitActionBarWhenNarrow"
效果图如下:

六 启用程序图标导航

为了将应用程序图标转变成可以点击的图标,可以调用ActionBar的如下方法。

  1.  setDisplayHomeAsUpEnabled(true);  //设置是否将应用程序图标转变成可点击的图标,并在图标上添加一个向左的箭头。    
  2.  setDisplayHomeAsUpEnabled(true)  //设置是否显示应用程序图标4
  3.  setHomeButtonEnable(true) //设置是否讲应用程序图标转变成可点击的按钮
  4.  当点击应用程序图标,相当于点击了一个id是android.R.id.home的菜单项,然后进行进一步的处理,比如使用Intent对象回到主Activity


   注意:第3个方法,在4.0之前默认是true,从4.0开始默认是false,如果想能够点击必须调用该方法。但是如果调用了第1个方法设置为true,则第3个方法也会被设置为true

代码块:

getActionBar().setDisplayHomeAsUpEnabled(true);

注意

    如果你要通过应用程序图标的响应来返回主Activity,那么就应该在Itent对象中包括FLAG_ACTIVITY_CLEAR_TOP标识(和SingleTask的作用是一样的)。用这个标记,如果你要启动的Activity在当前任务中已经存在,那么,堆栈中这个Activity之上的所有的Activity都有被销毁,并且把这个Activity显示给用户。添加这个标识往往是重要的,因为返回主Activity相当与一个回退的动作,因此通常不应该再创建一个新的主Activity的实例,否则,最终可能会在当前任务中产生一个很长的拥有多个主Activity的堆栈

Intent intent=new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
      如果不添加这个标志的话,当你不断点击应用程序图标的时候,比如路径是MainActivity->Second Activity ->MainActivity->Second Activity ....

再点击回退键的时候,会按照上述的反向依次退出,给用户的体验会不好。

七 改变ActionBar背景色

首先在style.xml文件中,自定义背景,如下:
<resources>
     <style name="AppTheme" parent="android:Theme.Light" />
     <drawable name="BackBar">#ff00</drawable>
     ......
 </resources>

使用修改setBackgroundDrawable背景色:

//改变ActionBar的背景色
actionBar.setBackgroundDrawable(getDrawable(R.drawable.action_bg));

八 实现Tab导航

       ActionBar最常用的功能就是实现Tab导航,ActionBar在顶端生成多个Tab标签,当用户点击某个Tab标签时,系统会根据用户点击事件导航指定的Tab界面,ActionBar实现Tab导航步骤如下:

(1)调用ActionBar的setNavigationMode(ActionBar.NAVIGATION_MODE_TABS)函数,设置Tab导航方式;

(2)调用ActionBar的addTab()函数,添加过个Tab标签,并且为每个Tab标签添加点击事件;

 而Tab的常用方法有:

setText()设置标题
setIcon()设置图标
setTabListener();设置监听器
setTag(Int fag );设置标志;

1  设置ActionBar为Tab导航

        actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

2 创建Fragment

        fragment1 = new ActionFragment();
        fragment2 = new ActionFragment2();
        fragment3 = new ActionFragment3();

3 创建Tabs

      ActionBar.Tab tab = actionBar.newTab()
                .setText("标题1")
                .setIcon(R.mipmap.ic_launcher)
                .setTabListener(this)
                .setTag(1);

        ActionBar.Tab tab2 = actionBar.newTab()
                .setIcon(R.mipmap.ic_launcher)
                .setText("标题2")
                .setTabListener(this)
                .setTag(2);

        ActionBar.Tab tab3 = actionBar.newTab()
                .setText("标题3")
                .setIcon(R.mipmap.ic_launcher)
                .setTabListener(this)
                .setTag(3);

        actionBar.addTab(tab);
        actionBar.addTab(tab2);
        actionBar.addTab(tab3);
        actionBar.setSelectedNavigationItem(1);//设置第一个默认的item

4 设置Tab监听实现切换tab

  @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
        switch ((Integer)tab.getTag()){
            case 1:
                ft.replace(R.id.frame_action_container,fragment1);
                break;
            case 2:
                ft.replace(R.id.frame_action_container,fragment2);
                break;
            case 3:
                ft.replace(R.id.frame_action_container,fragment3);
                break;
        }
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
        switch ((Integer)tab.getTag()){
            case 1:
                ft.remove(fragment1);
                break;
            case 2:
                ft.remove(fragment2);
                break;
            case 3:
                ft.remove(fragment3);
                break;
        }
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {

    }

效果图:


完整示例源码点击查看。

九 实现下来式导航

ActionBar实现下拉式导航步骤如下:

(1)调用ActionBar的setNavigationMode(ActionBar.NAVIGATION_MODE_LIST)函数,设置Tab导航方式;

(2)调用ActionBar的setLIstNavigationCallBacks(SpinnerAdapter adapter,ActionBar.OnNavigationListener callBack)函数添加列表项

1 设置导航模式
//获取该Activity的ActionBar:
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
2 创建Fragment集合
//fragments为 ArrayList<Fragment> fragments = new ArrayList<>()
fragments.add(new ActionFragment());
fragments.add( new ActionFragment2());
fragments.add( new ActionFragment3());
3 创建Adapter
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,
	android.R.layout.simple_list_item_1,android.R.id.text1,new String[]{"第一页","第二页","第三页"});
添加列表项并设置监听
actionBar.setListNavigationCallbacks(arrayAdapter, new ActionBar.OnNavigationListener() {
	@Override
	public boolean onNavigationItemSelected(int itemPosition, long itemId) {
		if (currentFragmentIndex >=0 && currentFragmentIndex < fragments.size()){
			fragments.get(currentFragmentIndex).onStop();
		}
		switch (itemPosition){
		   case 0:
		     if (currentFragmentIndex != 0){
			fragmentTransaction = fragmentManager.beginTransaction();
			if (!fragments.get(0).isAdded()){
			//如果要显示的Fragment还没有添加过,则需要添加到fragmentTransaction中
			fragmentTransaction.add(R.id.frame_action_container,fragments.get(0));
		     }else {//如果要显示的Fragment已经添加过,则隐藏当前的fragment,展现要显示的Fragment
			fragments.get(0).onStart();
			if (currentFragmentIndex >=0 && currentFragmentIndex < fragments.size()){
			     fragmentTransaction.hide(fragments.get(currentFragmentIndex));
			}
			fragmentTransaction.show(fragments.get(0));
		    }
			//提交业务
		   fragmentTransaction.commit();
		   //保存当前的Fragment的索引
		   currentFragmentIndex = 0;
		 }
		  break;
		case 1:
                  //同上,只是把上面的0换为1
		  break;	
		case 2:
		 //同上,只是把上面的0换为2	
		  break;
		}
		return false;
	}
});
效果图:

完整源码点击查看。

十 ActionBar获取失败解决办法

 检查 Theme
     检查你的应用是否设置了没有 ActionBar 的主题Theme,或者直接设置了 NoActionBar或NoTitleBar 属性,主要要检查这几点:
(1)检查 AndroidManifest.xml 中的标签中的theme属性
@android:style/Theme.NoTitleBar
(2)检查style的子标签是否含有如下内容   
<item name="windowActionBar">false</item> 
<item name="android:windowNoTitle">true</item>
(3) 检查 theme 属性值是为@android:style/xxx还是xxx
        < style name = "AppTheme" parent = "Theme.AppCompat.Light.DarkActionBar" >
       <!--    这时需要改为@android:style/xxx 例如 @android:style/Theme.Holo.Light -->
     </style>
      这样的属性都会使应用中的 ActionBar消失,切记,如果你要使用ActionBar,则一定要清除掉这些Theme属性设置,如果你的项目中 res 目录下除了 values 目录外,还有其他的res/values-v11,style/values-v14等,则这些目录中的 styles.xml 都需要检查一下,最后再检查下 Activity 代码中是否动态设置了全屏或者不显示TitleBar,代码如下:
requestWindowFeature(Window.FEATURE_NO_TITLE); 
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 
     上面的两句代码,上面一句设置Activity不显示TitleBar, 下一句则设置Activity为全屏模式,这两句代码都会导致 ActionBar 
无法显示,从而使 getActionBar()获取失败,如果你的项目中的 Activity 有父一级别的 Activity,则也需要将父一级别的Activity中的NoTitle和全屏代码注释掉;
检查 Theme 是否支持 ActionBar
      如果你不确定你的应用所用的主题 Theme 是否支持 ActionBar,可以在 res/values.xml 文件中设置为Theme.AppCompat,这是 AppCompat 中的Theme主题,可以保证低版本Android上也可以使用 ActionBar。
      另外,在 Acticity 中获取 ActionBar 的时候(getActionBar()或getSupportBar()), 需要在 setContentView(R.layout.main)之后调用。
注意:
      res/values,res/values-v11,res/values-v14等目录中的style都要进行style设置,并且都要注意:不要设置成第1条中会禁止ActionBar显示的主题,但可以设置为不同种类的主题。
getActionBar与 getSupportActionBar
     如果你的项目使用的是 android.app.ActionBar,则需要把你应用的最低支持版本改为11(Android 3.0),使用 getActionBar() 来获取ActionBar,如果你的项目要支持Android 3.0以下,则你的项目需要引入最新的 AppCompat 兼容包,然后将 ActionBar引用改为 android.support.v7.app.ActionBar,并使用 getSupportActionBar 来获取 ActionBar;
4 其它
原因
     除了以上的原因可能导致 ActionBar 获取为空的话,还有其他的原因导致 getActionBar() 获取失败,例如我在网上查找的时候,有人的项目是在Android SDK 2.2上新建的,当他使用 ActionBar 的时候将 AndroidManifest.xml 中的 minSdkVersion设置为11后(),发现 getActionBar() 获取失败是因为项目中没有 res/values-v11和res/values-v14和其中的style.xml文件,我最近遇到的 getActionBar() 为null是在 Eclipse 中导入了一个别人发给我的项目,但是在他的电脑上编译运行的apk getActionBar(), 但在我的电脑上则不行,试了上面的几种方法也不行,最后,我把这个项目导入到了 Android Studio 中,终于可以正常运行了。

ActionBar示例源码都在这里:
















  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值