Android ActionBar使用

Posted dsliang12

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android ActionBar使用相关的知识,希望对你有一定的参考价值。

转载请标明出处:
http://blog.csdn.net/zq2114522/article/details/50576158
本文出自:【梁大盛的博客】

android ActionBar使用

很久之前看Google官方一个Note笔记本代码.那时候觉得很神奇程序上面那一栏东西会随着Activity的跳转进行切换按钮,并且当长按那些按钮的时候会有提示按钮的功能.那时候还没意识到那就是ActionBar.当然那时候只是一个菜鸟那时候也没怎么了解过ActionBar,就是觉得很神奇.很诧异到底是什么实现的.最后时间长了很没深究.这几天有空档把ActionBar英文文档彻头彻尾的看了一遍.突然想起以前不理解的东西原来就是ActionBar.在后面的版本因为ActionBar自身的原因引入ToolBar那也是后话了,但是必须知道ToolBar也是基于ActionBar很多功能来实现的.

ActionBar在Android 3.0(Api 11)引入的一个概念.那就意味着Android 3.0以前的FrameWork没有ActionBar存在的.Android 3.0推出的时候,也推出support library借此支持旧版本的机器(Android 2.1-Api 7及其以上的版本)能用上ActionBar等新东西.

添加ActionBar

Android 3.0为分界线.如果只运行在Android 3.0以后的机器可以直接使用ActionBar无需导入其他support library.但是为了更好的兼容性,一般都推荐使用support library借此能支持Android 2.1以上的机器.

  • 如果你的程序只允许在Android 3.0及其以上的机器(minSdkVersion 11)

    使用的包:
    import android.app.ActionBar

    Activity只需继承android.app.Activity

    “application”或者”activity”的android:theme属性必须是Theme.Holo(或者是Theme.Holo的子类)

  • 如果你的程序支持在Android 2.1及其以上的机器(minSdkVersion 7)
    使用的包:
    import android.support.v7.app.ActionBar

    Activity必须继承android.support.v7.app.AppCompatActivity或者android.support.v7.app.ActionBarActivity(AppCompatActivity和ActionBarActivity的区别.早期通过继承ActionBarActivity实现低版本支持ActionBar.在Support Library更新到v22.1的时候引入AppCompatActivity代替ActionBarActivity.在以后版本我们使用ActionBarActivity即可.)

    “application”或者”activity”的android:theme属性必须是Theme.AppCompat(或者是Theme.AppCompat的子类)

添加ActionBar需要关注的地方就是这三点.

简单代码(使用support library,以便支持到更低的版本)
MainActivity.java

package com.example.dsliang.actionbardemo;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;

public class MainActivity extends ActionBarActivity 

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    


AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.dsliang.actionbardemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:gravity="center"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ActionBar!" />
</LinearLayout>

build.gradle

apply plugin: 'com.android.application'

android 
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig 
        applicationId "com.example.dsliang.actionbardemo"
        minSdkVersion 7
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    
    buildTypes 
        release 
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        
    


dependencies 
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'


运行在Android 4.1.1是成长着样子的


运行在Android 2.3.7是成长着样子的

隐藏、显示ActionBar

获取ActionBar实例

如果使用FrameWork的Actionbar在onCreate函数通过getActionBar函数获取ActionBar的实例.(如果使用support library库需要使用getSupportActionBar函数获取ActionBar的实例)

注意:如果当你使用support library库的时候使用getActionBar函数获取ActionBar的实例.返回的值是null.反之也是同理.(getActionBar函数 - minSdkVersion 11)
  • 隐藏Actionbar
    ActionBar.hide()函数
  • 显示ActionBar
    ActionBar.show()函数

    注意:默认每次显示/隐藏ActionBar都会导致布局重新加载.视觉效果上会导致隐藏的时候整个布局给拉伸一次,显示又会导致压缩一次.针对需要频繁隐藏/显示ActionBar的情况可以将ActionBar设置成Overlay模式(覆盖在layout层上,像FrameLayout的效果.即使隐藏/显示也不会导致布局重新加载).
    

隐藏/显示效果:

隐藏/显示明显看到布局有重新加载.

ActionBar OverLyaout模式

(只是修改了AndroidManifest.xml和styles.xml)
AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.dsliang.actionbardemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="windowActionBarOverlay">true</item>
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>


</resources>

效果:

Action Button

在Android 3.0以后一个很值得注意到地方,他取消了菜单键并且将菜单功能集成到ActionBar里面了.由此Action Button诞生.Action Button是将本来的六宫格菜单都搬到ActionBar的右侧.在能显示的前提下都将菜单已标题或者图标加标题的形式显示在ActionBar的右侧.但是众所周知,ActionBar控件也不是很大.ActionBar会将无法容纳的Action Button放置在Overflow按钮里面(三个小点的图标).


很久之前的菜单键是这样的(Android 2.3.7)


现在是这样的(Android 4.1.1)

定义菜单键(Action Button)

  • 定义菜单键的xml文件(一般放置在res/menu/目录下)

    根节点”menu”并且包含子节点”item”,在子节点”item”定义菜单键的属性.包括:title-标题,icon-图标,id-id号,showAsAction-按钮的表现形式,等等.

    注意:在Android 3.0以前的版本,FrameWork里面并没有showAsAction这个属性.使用这属性的使用要定义命名空间.
    
  • 调用onCreateOptionMenu函数加载Action Button

menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_search"
        app:showAsAction="always"
        android:icon="@android:drawable/ic_menu_search"
        android:title="search" />
    <item
        android:id="@+id/menu_camera"
        android:icon="@android:drawable/ic_menu_camera"
        app:showAsAction="ifRoom|withText"
        android:title="camera" />
    <item
        android:id="@+id/menu_add"
        android:icon="@android:drawable/ic_menu_add"
        app:showAsAction="ifRoom"
        android:title="add" />
    <item
        android:id="@+id/menu_delete"
        android:icon="@android:drawable/ic_menu_delete"
        app:showAsAction="never"
        android:title="delete" />
</menu>

Activity类实现onCreateOptionsMenu方法即可

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 

        getMenuInflater().inflate(R.menu.menu, menu);

        return super.onCreateOptionsMenu(menu);
    

showAsAction属性解析
always:显示在ActionBar,但是只有有空间才会显示,没空间的情况下会放置在OverFlow里面
ifRoom:如果有足够空间则显示在ActionBar,没空间的情况下会放置在OverFlow里面
never:安置在OverFlow里面
withText:如果有足够空间把标题也显示在图标右侧并且用”|”号分割将图标和标题分割开.(Action Button Icon属性是可选的.如果显示在ActionBar,那么只会显示图标.添加withText以后如果显示在ActionBar的时候有足够空间会把标题和图标以前显示.当显示在ActionBar并且没显示标题的时候,长按图标会弹出标题.当Action Button显示在OverFlow的时候只会显示标题不会显示图标.)

效果图:

响应Action Button点击事件

继承Activity的onOptionsItemSelected函数,当点击Action Button的时候会调用onOptionsItemSelected函数通过MenuItem.getId可以获取到哪一个Action Button给点击.

注意:onOptionsItemSelected函数的返回值.如果返回真那就意味着已经把这一个事件消耗了.如果返回假这事件会继续传递下去(传递到Fragment).
注意:不仅仅可以通过继承Activity的onOptionsItemSelected函数添加Action Button.还可以通过继承Fragment的onOptionsItemSelected函数实现添加Action Button.区别在于通过Fragment添加的Action Button项会排列在通过Activity添加的Action Button后面.当用户点击Action Button的时候会调用activity的onOptionsItemSelected函数.如果activity的onOptionsItemSelected返回true表明此事件已经处理了不在传递.如果activity的onOptionsItemSelected返回false那么会继续调用Fragment的onOptionsItemSelected函数继续处理这次点击事件.
public class MainActivity extends AppCompatActivity 
 ...
 public boolean onOptionsItemSelected(MenuItem item) 

        switch (item.getItemId()) 
            case R.id.menu_add:
                //Do something
                return true;
            case R.id.menu_camera:
                //Do something
                return true;
            case R.id.menu_delete:
                //Do something
                return true;
            case R.id.menu_search:
                //Do something
                return true;
        

        return super.onOptionsItemSelected(item);
    
 


4.1.1 Overflow效果


2.37 Overflow效果

注意:Overflow运行效果区别原因.如果有menu按钮那么不会再显示Overflow按钮

导航栏

ActionBar除了集成了Action Button之外还暗藏一个导航栏.
在使用ActionBar的Tab功能之前,你的布局需要预留一个地方给Tab所需显示的控件.一般做法是使用FrameLayout显示Tab需要显示的内容.切换Tab的时候将Tab对于的Fragment放置到该容器当中.
使用方法:

  • 调用getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS),此函数的功能是把Tab栏显示出来.

  • 实现ActionBar.TabListener接口

    onTabSelected - Tab给选择的时候调用
    onTabUnselected - Tab反选择的时候调用
    onTabReselected - Tab选中状态再给选择的时候调用(一般不做处理)

  • 实现ActionBar.Tab,ActionBar.Tab代表一个Tab选项

  • 调用ActionBar.addTab函数把Tab添加到ActionBar

代码:

MainActivity.java

package com.example.dsliang.actionbardemo;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity 

    ActionBar mActionBarSupport;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActionBar.Tab tab;

        mActionBarSupport = getSupportActionBar();
        mActionBarSupport.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        tab = mActionBarSupport.newTab()
                .setText(R.string.tab_sports)
                .setTabListener(new TabListener<TabSportFragment>(this, "体育新闻", TabSportFragment.class));
        mActionBarSupport.addTab(tab);
        tab = mActionBarSupport.newTab()
                .setText(R.string.tab_international)
                .setTabListener(new TabListener<TabInternationalFragment>(this, "国际新闻", TabInternationalFragment.class));
        mActionBarSupport.addTab(tab);
        tab = mActionBarSupport.newTab()
                .setText(R.string.tab_focus)
                .setTabListener(new TabListener<TabFocusFragment>(this, "今日焦点", TabFocusFragment.class));
        mActionBarSupport.addTab(tab);
    

    class TabListener<T extends Fragment> implements ActionBar.TabListener 

        private Fragment mFragment;
        private final Activity mActivity;
        private final String mTag;
        private final Class<T> mClass;


        public TabListener(Activity activity, String tag, Class<T> clz) 
            mActivity = activity;
            mTag = tag;
            mClass = clz;
        

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

            if (mFragment == null) 
                mFragment = Fragment.instantiate(mActivity, mClass.getName());
                ft.add(R.id.fragment_content, mFragment, mTag);
             else 
                ft.attach(mFragment);
            

        


        @Override
        public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) 
            if (mFragment != null) 
                ft.detach(mFragment);
            
        

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

        
    



TabFocusFragment.java

package com.example.dsliang.actionbardemo;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * Created by dsliang on 2016/1/25.
 */
public class TabFocusFragment extends Fragment 
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 

        View view;
        TextView textView;

        view = inflater.inflate(R.layout.tab_fragment_layout, container, false);
        textView = (TextView) view.findViewById(R.id.txtTextView);
        textView.setText(R.string.tab_focus);

        return view;
    

TabInternationalFragment.java

package com.example.dsliang.actionbardemo;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * Created by dsliang on 2016/1/25.
 */
public class TabInternationalFragment extends Fragment 
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 

        View view;
        TextView textView;

        view = inflater.inflate(R.layout.tab_fragment_layout, container, false);
        textView = (TextView) view.findViewById(R.id.txtTextView);
        textView.setText(R.string.tab_international);

        return view;
    

TabSportFragment.java

package com.example.dsliang.actionbardemo;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * Created by dsliang on 2016/1/25.
 */
public class TabSportFragment extends Fragment 
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 

        View view;
        TextView textView;

        view = inflater.inflate(R.layout.tab_fragment_layout, container, false);
        textView = (TextView) view.findViewById(R.id.txtTextView);
        textView.setText(R.string.tab_sports);

        return view;
    

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/fragment_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></FrameLayout>

</LinearLayout>

tab_fragment_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/txtTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="25sp" />

</LinearLayout>

strings.xml

<resources>
    <string name="app_name">ActionBarDemo</string>
    <string name="tab_sports">体育新闻</string>
    <string name="tab_international">国际新闻</string>
    <string name="tab_focus">今日焦点</string>

</resources>

TabFocusFragment、TabInternationalFragment、TabSportFragment三个Fragment代码是基本一样的。实质应该用不同的Fragment代替,仅作示范。
具体代码里面已经很清楚了,就不再细说了。(除了导航栏意外还有另一种下拉导航栏,基本都是大同小异的。)

效果:

Action View

除了Action Button和Tab之外还有Action View。
什么是Action View?
我们可以在ActionBar中嵌入我们自定义的Layout或者View控件,称之Action View。
有什么用途?
在不改变ActionBar、Fragment和Activity的前提下快速完成某些操作,如:搜索等(当然在ActionBar内嵌一个SearchView是最常见的)。
使用方法:

  • 和定义Action Buton基本一样,就是多了一个actionViewClass属性(collapseActionView表明将ActionView折叠成一个ActionButton)

    例如:app:showAsAction=”ifRoom|collapseActionView”

     注意:actionViewClass属性也是在低版本没定义的。需要在xml文件新建命名空间
    
  • 查找Actoin View对应的View

    代码

getMenuInflater().inflate(R.menu.main_activity_actions, menu);
    MenuItem searchItem = menu.findItem(R.id.action_search);
    SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
注意:MenuItemCompat.getActionView(searchItem)是Api 7提供的函数。Api 11以后可以使用menu.findItem(R.id.action_search).getActionView()

- 定义Action View回调事件
通过MenuItemCompat.setOnActionExpandListener设置折叠/打开监听函数
(具体可以看后面提供的代码)

代码

MainActivity.java

package com.example.dsliang.actionbardemo;

import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity 

    ActionBar mActionBarSupport;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActionBar.Tab tab;

        mActionBarSupport = getSupportActionBar();
    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 

        MenuItem menuItem;
        SearchView searchView;

        getMenuInflater().inflate(R.menu.menu, menu);
        menuItem = menu.findItem(R.id.menu_search);
        searchView = (SearchView) MenuItemCompat.getActionView(menuItem);

        //可以针对searchView设置相应的监听函数
        //....searchView

        //设置折叠监听函数
        MenuItemCompat.setOnActionExpandListener(menuItem, new MenuItemCompat.OnActionExpandListener() 
            @Override
            public boolean onMenuItemActionExpand(MenuItem item) 
                Toast.makeText(MainActivity.this, "ActionView open", Toast.LENGTH_SHORT).show();

                return true;
            

            @Override
            public boolean onMenuItemActionCollapse(MenuItem item) 
                Toast.makeText(MainActivity.this, "ActionView collapse", Toast.LENGTH_SHORT).show();

                return true;
            
        );

        return super.onCreateOptionsMenu(menu);
    




menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_search"
        app:showAsAction="ifRoom|collapseActionView"
        android:icon="@android:drawable/ic_menu_search"
        android:title="search"
        app:actionViewClass="android.support.v7.widget.SearchView"/>
    <item
        android:id="@+id/menu_camera"
        android:icon="@android:drawable/ic_menu_camera"
        app:showAsAction="ifRoom"
        android:title="camera" />
    <item
        android:id="@+id/menu_add"
        android:icon="@android:drawable/ic_menu_add"
        app:showAsAction="ifRoom"
        android:title="add" />
    <item
        android:id="@+id/menu_delete"
        android:icon="@android:drawable/ic_menu_delete"
        app:showAsAction="ifRoom"
        android:title="delete" />
</menu>

效果:

Action View 效果

总结:这一篇写的挺多的.遗憾AcionBar Home按钮没写.打算等有时间继续写下去.此外下一篇写Menu的使用.因为ActionBar使用必定就牵涉到Menu了!

参考


1:ActionBar http://android.xsoftlab.net/guide/topics/ui/actionbar.html
2:ActionBar http://android.xsoftlab.net/reference/android/support/v7/app/ActionBar.html
3:Menu http://android.xsoftlab.net/reference/android/view/Menu.html
4:如何在有菜单键的机器显示OverFlow按钮 http://www.jb51.net/article/52468.htm
5:Android ActionBar完全解析,使用官方推荐的最佳导航栏 http://itindex.net/detail/49902-android-actionbar-%E5%AE%8C%E5%85%A8
6:ActionBar侧拉栏 http://blog.csdn.net/jjwwmlp456/article/details/41206513

以上是关于Android ActionBar使用的主要内容,如果未能解决你的问题,请参考以下文章

Android 实现ActionBar定制

Android中活动条ActionBar的详细使用

如何使用android-support-V7包中ActionBar

Android界面编程--使用活动条(ActionBar)

Android界面编程--使用活动条(ActionBar)--实现Tab导航

使用 ActionBar 旋转 Android 的双片段