转载请标明出处:
http://blog.csdn.net/zq2114522/article/details/50576158;
本文出自:【梁大盛的博客】
很久之前看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等新东西.
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
<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
<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'
}
获取ActionBar实例
如果使用FrameWork的Actionbar在onCreate函数通过getActionBar函数获取ActionBar的实例.(如果使用support library库需要使用getSupportActionBar函数获取ActionBar的实例)
注意:如果当你使用support library库的时候使用getActionBar函数获取ActionBar的实例.返回的值是null.反之也是同理.(getActionBar函数 - minSdkVersion 11)
显示ActionBar
ActionBar.show()函数
注意:默认每次显示/隐藏ActionBar都会导致布局重新加载.视觉效果上会导致隐藏的时候整个布局给拉伸一次,显示又会导致压缩一次.针对需要频繁隐藏/显示ActionBar的情况可以将ActionBar设置成Overlay模式(覆盖在layout层上,像FrameLayout的效果.即使隐藏/显示也不会导致布局重新加载).
ActionBar OverLyaout模式
(只是修改了AndroidManifest.xml和styles.xml)
AndroidManifest.xml
<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
-- Base application theme. -->
在Android 3.0以后一个很值得注意到地方,他取消了菜单键并且将菜单功能集成到ActionBar里面了.由此Action Button诞生.Action Button是将本来的六宫格菜单都搬到ActionBar的右侧.在能显示的前提下都将菜单已标题或者图标加标题的形式显示在ActionBar的右侧.但是众所周知,ActionBar控件也不是很大.ActionBar会将无法容纳的Action Button放置在Overflow按钮里面(三个小点的图标).
定义菜单键(Action Button)
定义菜单键的xml文件(一般放置在res/menu/目录下)
根节点”menu”并且包含子节点”item”,在子节点”item”定义菜单键的属性.包括:title-标题,icon-图标,id-id号,showAsAction-按钮的表现形式,等等.
注意:在Android 3.0以前的版本,FrameWork里面并没有showAsAction这个属性.使用这属性的使用要定义命名空间.
调用onCreateOptionMenu函数加载Action Button
menu.xml
<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);
}
}
注意: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(this, "体育新闻", TabSportFragment.class));
mActionBarSupport.addTab(tab);
tab = mActionBarSupport.newTab()
.setText(R.string.tab_international)
.setTabListener(new TabListener(this, "国际新闻", TabInternationalFragment.class));
mActionBarSupport.addTab(tab);
tab = mActionBarSupport.newTab()
.setText(R.string.tab_focus)
.setTabListener(new TabListener(this, "今日焦点", TabFocusFragment.class));
mActionBarSupport.addTab(tab);
}
class TabListener implements ActionBar.TabListener {
private Fragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class mClass;
public TabListener(Activity activity, String tag, Class 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
<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
<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
<string name="app_name">ActionBarDemostring>
<string name="tab_sports">体育新闻string>
<string name="tab_international">国际新闻string>
<string name="tab_focus">今日焦点string>
TabFocusFragment、TabInternationalFragment、TabSportFragment三个Fragment代码是基本一样的。实质应该用不同的Fragment代替,仅作示范。
具体代码里面已经很清楚了,就不再细说了。(除了导航栏意外还有另一种下拉导航栏,基本都是大同小异的。)
除了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
<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>
总结:这一篇写的挺多的.遗憾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