Android开发笔记(二十)顶部导航栏ActionBar

标题栏ActionBar

ActionBar是在Android3.0之后引入的,所以Android2.x之前的版本不能直接使用ActionBar。现在ActionBar广泛用做APP的顶部导航栏,它在布局上主要分为三部分:左边是返回区域,包括logo、返回箭头、左侧标题等等;右边是菜单区域,放的是溢出菜单OverflowMenu的各菜单项;中间是条件区域,包括导航项Navigation(下拉列表与标签切换)、搜索框SearchView,以及可自定义的定制视图CustomView。


显示或者关闭ActionBar的方式有如下几种:
1、在AndroidManifest.xml中给activity设置无标题栏的主题,就关闭ActionBar。否则就显示
<activity android:theme="@android:style/Theme.Holo.NoActionBar"> 
2、在styles.xml的当前主题中加入一个项android:windowNoTitle,为true时表示关闭ActionBar;为false表示显示
<item name="android:windowNoTitle">true</item>
3、在Activity代码的setContentView之前加入下面代码,就关闭ActionBar。否则就显示
requestWindowFeature(Window.FEATURE_NO_TITLE);
4、在Activity代码中获得ActionBar实例,调用该实例的hide方法表示关闭ActionBar;调用show方法表示显示
ActionBar actionBar = getActionBar();
if (actionBar != null) {
    actionBar.hide();  //隐藏ActionBar
    actionBar.show();  //显示ActionBar
}


ActionBar的基本设置

ActionBar其上各控件的开关设置说明如下:
setDisplayUseLogoEnabled : 是否在左侧返回区域显示logo,默认显示
setDisplayHomeAsUpEnabled : 是否在左侧返回区域显示返回箭头,默认不显示
setDisplayShowTitleEnabled : 是否在左侧返回区域显示左侧标题,默认显示APP名称
setTitle : 设置左侧标题的文本
setBackgroundDrawable : 设置ActionBar的背景图像
setDisplayShowCustomEnabled : 是否在中间条件区域显示定制视图
setNavigationMode : 设置导航项的样式,NAVIGATION_MODE_STANDARD表示不显示,NAVIGATION_MODE_LIST表示显示下拉列表,NAVIGATION_MODE_TABS表示显示标签切换。默认不显示


setDisplayOptions : 设置显示的选项参数,以“|”连接,各参数与设置函数的对应关系如下:
DISPLAY_USE_LOGO : 对应setDisplayUseLogoEnabled
DISPLAY_SHOW_HOME : 无对应函数,该参数表示需要显示左侧返回区域
DISPLAY_HOME_AS_UP : 对应setDisplayHomeAsUpEnabled
DISPLAY_SHOW_TITLE : 对应setDisplayShowTitleEnabled
DISPLAY_SHOW_CUSTOM : 对应setDisplayShowCustomEnabled


溢出菜单OverflowMenu

OverflowMenu其实就是把选项菜单OptionsMenu搬到了页面右上方,具体使用方法与Menu是一样的,所以就不多说了。下面列一下几个注意点:
1、菜单项的布局定义中,要把showAsAction属性设置好。该属性的取值类型主要有:
ifRoom : 如果ActionBar右侧有空间,则该项直接显示在ActionBar上面,不再放入溢出菜单。
never : 从不在ActionBar上直接显示,一直放在溢出菜单里面。
always : 总是在ActionBar上显示。
withText : 如果能在ActionBar上显示,则除了显示该项的图标,还要显示该项的文字说明。
collapseActionView : 不常用,而且比较麻烦,若有兴趣可自行查阅资料。
2、Android手机一般都有物理按键,按下物理按键的菜单键,有的手机在顶部显示选项菜单而不是在右上角显示,有的手机干脆不显示任何菜单(常见于Android4.2.2以下系统)。所以为了兼容不同手机不同系统,我们需要对溢出菜单做特殊处理,将物理按键加以屏蔽,强制显示OverflowMenu。
3、放入溢出菜单的菜单项,Android默认不在菜单文字左侧显示图标,就算在菜单布局文件中设置了android:icon也不管用。所以要想在菜单列表中显示左侧图标,需要调用MenuBuilder的setOptionalIconsVisible方法(MenuBuilder在Android内核中,未开放出来,只能通过反射机制来调用)。




导航项Navigation

使用导航项需要在ActionBar中将其设置为具体模式(setNavigationMode),目前ActionBar支持两种导航模式:
1、NAVIGATION_MODE_LIST: 表示采用下拉列表模式;
2、NAVIGATION_MODE_TABS: 表示采用标签切换模式;
下拉列表模式的使用方法类似Spinner,也要设置列表文本的ArrayAdapter与监听器。不同的是Spinner的监听器继承自OnItemSelectedListener,而Navigation的监听器继承自OnNavigationListener。
标签切换模式在实际开发中用得不多,类似效果一般采用底部标签栏或者ViewPager实现。


定制视图CustomView

定制视图用于在ActionBar上显示一些个性化内容,比如说,ActionBar自带的标题文字位于左侧区域,而且也不能调整文字大小、颜色等等,如果我们想把标题文本挪到中间,还要设置文字样式的话,就得使用定制视图了。
使用定制视图需要在ActionBar中将其设置为可用(setDisplayShowCustomEnabled),同时要通过setDisplayOptions来设置DISPLAY_SHOW_CUSTOM。
定制视图的布局与普通布局一样,都在layout目录下,从布局文件中获取并修改完成视图后,调用ActionBar的setCustomView方法就完成了定制。
另外,更换左侧返回区域的返回箭头图标,可通过ActionBar的setIcon来实现。但该方法在Android4.4.2之后才支持,之前版本的系统仍然不支持定制左侧返回图标。


搜索框SearchView

搜索框有些复杂,实现步骤大致如下:
1、在菜单布局文件中定义搜索项:
    <item
        android:id="@+id/menu_search"
        android:orderInCategory="1"
        android:icon="@drawable/ic_search"
        android:showAsAction="ifRoom"
        android:title="搜索"
        android:actionViewClass="android.widget.SearchView" />

2、在res\xml目录下新建searchable.xml,设置搜索框的样式:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="@string/please_input"
    android:inputType="text"
    android:searchButtonText="@string/search" />

3、在AndroidManifest.xml中加入一个搜索结果activity的定义,需要指定action和meta-data,例如:
        <activity android:name=".SearchResultActvity" android:label="@string/app_name" >
            <intent-filter> 
                <action android:name="android.intent.action.SEARCH"/>
            </intent-filter> 
            <meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/>
        </activity>

4、在菜单代码中初始化搜索框,并关联搜索动作对应的activity(本例中的activity是SearchResultActvity)
	private void initSearchView(Menu menu) {
	    SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
	    if(searchView == null){
	        Log.d(TAG, "Fail to get SearchView.");
	    } else {
	    	//设置搜索框默认自动缩小为图标
	    	searchView.setIconifiedByDefault(true);
	    	//设置是否显示搜索按钮。搜索按钮只显示一个箭头图标,Android暂不支持显示文本。
	    	//查看Android源码,搜索按钮用的控件是ImageView,所以。。。
	    	searchView.setSubmitButtonEnabled(true);
	    	//设置搜索框内的默认显示的提示文本
	    	//searchView.setQueryHint(getResources().getString(R.string.please_input));
	    	
	        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
	        //关联搜索结果的activity
	        ComponentName cn = new ComponentName(this, SearchResultActvity.class);
	        //从activity中获取相关搜索信息,就是searchable的xml设置
	        SearchableInfo info = searchManager.getSearchableInfo(cn); 
	        if(info == null){ 
	            Log.d(TAG, "Fail to get SearchResultActvity."); 
	        }      
	        //将activity的搜索信息与search view关联
	        searchView.setSearchableInfo(info); 
	    }
	}

5、编写搜索结果activity的代码,其中提取搜索关键字的代码片段如下:
        if(intent == null) {
            return; 
        } else {
            //如果是通过ACTION_SEARCH来调用,即如果通过搜索调用
            if(Intent.ACTION_SEARCH.equals(intent.getAction())){
            	//获取搜索内容
                String queryString = intent.getStringExtra(SearchManager.QUERY);
                tv_search_result.setText("您输入的搜索文字是:"+queryString);
            }  
        }


代码例子

下面是几个导航栏效果的代码例子
原生导航代码,包括溢出菜单和导航项
import java.util.Date;

import com.example.exmactionbar.util.Utils;

import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.ActionBar.OnNavigationListener;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import android.widget.Toast;

public class OriginActivity extends Activity {
	private static final String TAG = "OriginActivity";
	private TextView tv_origin;
	private String[] mDescArray = {"标点时间", "标点日期", "中文时间", "中文日期"};
	private String[] mmFormatArray = {"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd",
									"yyyy年MM月dd日HH时mm分ss秒", "yyyy年MM月dd日"};
	private String mFormat = mmFormatArray[0];
	private Date mNowTime = new Date();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_origin);
		tv_origin = (TextView) findViewById(R.id.tv_origin);
		getActionBar("原生页", R.drawable.actionbar_gradient_blue).show();
	}

	@SuppressLint("InflateParams")
	private ActionBar getActionBar(String title, int bgId) {
		ActionBar actionBar = this.getActionBar();
		if (actionBar != null) {
			//无论系统版本为何,无论有无物理按键,都强制显示选项菜单
			Utils.forceShowOverflowMenu(this);
			actionBar.setDisplayShowTitleEnabled(true);
			actionBar.setDisplayHomeAsUpEnabled(true);
			actionBar.setDisplayShowHomeEnabled(false);
			actionBar.setDisplayShowCustomEnabled(false);
			actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE|ActionBar.DISPLAY_HOME_AS_UP);
			if (bgId > 0) {
				actionBar.setBackgroundDrawable(getResources().getDrawable(bgId));
			}
			actionBar.setTitle(title);
			//允许在导航栏上显示下拉框,另一种NAVIGATION_MODE_TABS表示标签页切换
			actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
			ArrayAdapter<String> adapter = new ArrayAdapter<String>(
					this, R.layout.spinner_item, mDescArray);
			adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
			actionBar.setListNavigationCallbacks(adapter, new navigationListener());
		} else {
			Toast.makeText(this, "无法获得ActionBar", Toast.LENGTH_SHORT).show();
		}
		return actionBar;
	}

	class navigationListener implements OnNavigationListener {
		@Override
		public boolean onNavigationItemSelected(int itemPosition, long itemId) {
			mFormat = mmFormatArray[itemPosition];
			tv_origin.setText("当前格式时间: "+Utils.getFormatDateTime(mNowTime, mFormat));
			return false;
		}
	}
	
    @Override  
    public boolean onMenuOpened(int featureId, Menu menu) {  
    	//显示菜单项左侧的图标
        Utils.setOverflowIconVisible(featureId, menu);  
        return super.onMenuOpened(featureId, menu);  
    }  
  
	@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 == android.R.id.home) {
			finish();
		} else if (id == R.id.menu_refresh) {
			mNowTime = new Date();
			tv_origin.setText("当前刷新时间: "+Utils.getFormatDateTime(mNowTime, mFormat));
			return true;
		} else if (id == R.id.menu_about) {
			Toast.makeText(this, "这个是顶部导航栏的演示demo", Toast.LENGTH_LONG).show();
			return true;
		} else if (id == R.id.menu_quit) {
			finish();
		}
		return super.onOptionsItemSelected(item);
	}

}



定制导航代码,包括溢出菜单和定制视图
import com.example.exmactionbar.util.Utils;

import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class CustomActivity extends Activity {
	private static final String TAG = "CustomActivity";
	private TextView tv_custom;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_custom);
		tv_custom = (TextView) findViewById(R.id.tv_custom);
		getActionBar("定制标题", R.drawable.actionbar_gradient_red).show();
	}

	@SuppressLint("InflateParams")
	private ActionBar getActionBar(String title, int bgId) {
		ActionBar actionBar = this.getActionBar();
		if (actionBar != null) {
			//无论系统版本为何,无论有无物理按键,都强制显示选项菜单
			Utils.forceShowOverflowMenu(this);
			actionBar.setDisplayShowTitleEnabled(false);
			actionBar.setDisplayHomeAsUpEnabled(true);
			actionBar.setDisplayShowHomeEnabled(true);
			actionBar.setDisplayShowCustomEnabled(true);
			if (bgId > 0) {
				actionBar.setBackgroundDrawable(getResources().getDrawable(bgId));
			}
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
				actionBar.setIcon(R.drawable.back_btn);
				actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM|ActionBar.DISPLAY_SHOW_HOME);
			} else {
				actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM|ActionBar.DISPLAY_SHOW_HOME|ActionBar.DISPLAY_HOME_AS_UP);
			}
			ActionBar.LayoutParams lp =new ActionBar.LayoutParams(
					ActionBar.LayoutParams.MATCH_PARENT,
					ActionBar.LayoutParams.WRAP_CONTENT,
					Gravity.CENTER);
			View v_titlebar = this.getLayoutInflater().inflate(R.layout.action_bar_title, null);
			actionBar.setCustomView(v_titlebar, lp);
			TextView tv_title = (TextView) v_titlebar.findViewById(R.id.tv_title);
			tv_title.setText(title);
		} else {
			Toast.makeText(this, "无法获得ActionBar", Toast.LENGTH_SHORT).show();
		}
		
		return actionBar;
	}

    @Override  
    public boolean onMenuOpened(int featureId, Menu menu) {  
    	//显示菜单项左侧的图标
        Utils.setOverflowIconVisible(featureId, menu);  
        return super.onMenuOpened(featureId, menu);  
    }  
  
	@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 == android.R.id.home) {
			finish();
		} else if (id == R.id.menu_refresh) {
			tv_custom.setText("当前刷新时间: "+Utils.getNowDateTime("yyyy-MM-dd HH:mm:ss"));
			return true;
		} else if (id == R.id.menu_about) {
			Toast.makeText(this, "这个是顶部导航栏的演示demo", Toast.LENGTH_LONG).show();
			return true;
		} else if (id == R.id.menu_quit) {
			finish();
		}
		return super.onOptionsItemSelected(item);
	}
}



搜索导航代码,包括溢出菜单和搜索框
import com.example.exmactionbar.util.Utils;

import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.Activity;
import android.app.SearchManager;
import android.app.SearchableInfo;
import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.SearchView;
import android.widget.TextView;
import android.widget.Toast;

public class SearchActivity extends Activity {
	private static final String TAG = "SearchActivity";
	private TextView tv_search;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_search);
		tv_search = (TextView) findViewById(R.id.tv_search);
		getActionBar(this, "搜索页", R.drawable.actionbar_gradient_blue).show();
	}

	@SuppressLint("InflateParams")
	public static ActionBar getActionBar(Activity act, String title, int bgId) {
		ActionBar actionBar = act.getActionBar();
		if (actionBar != null) {
			actionBar.setDisplayShowTitleEnabled(true);
			actionBar.setDisplayHomeAsUpEnabled(true);
			actionBar.setDisplayShowHomeEnabled(false);
			actionBar.setDisplayShowCustomEnabled(false);
			actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE|ActionBar.DISPLAY_HOME_AS_UP);
			if (bgId > 0) {
				actionBar.setBackgroundDrawable(act.getResources().getDrawable(bgId));
			}
			actionBar.setTitle(title);
		} else {
			Toast.makeText(act, "无法获得ActionBar", Toast.LENGTH_SHORT).show();
		}
		return actionBar;
	}
	
	private void initSearchView(Menu menu) {
	    SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
	    if(searchView == null){
	        Log.d(TAG, "Fail to get SearchView.");
	    } else {
	    	//设置搜索框默认自动缩小为图标
	    	searchView.setIconifiedByDefault(true);
	    	//设置是否显示搜索按钮。搜索按钮只显示一个箭头图标,Android暂不支持显示文本。
	    	//查看Android源码,搜索按钮用的控件是ImageView,所以。。。
	    	searchView.setSubmitButtonEnabled(true);
	    	//设置搜索框内的默认显示的提示文本
	    	//searchView.setQueryHint(getResources().getString(R.string.please_input));
	    	
	        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
	        //关联搜索结果的activity
	        ComponentName cn = new ComponentName(this, SearchResultActvity.class);
	        //从activity中获取相关搜索信息,就是searchable的xml设置
	        SearchableInfo info = searchManager.getSearchableInfo(cn); 
	        if(info == null){ 
	            Log.d(TAG, "Fail to get SearchResultActvity."); 
	        }      
	        //将activity的搜索信息与search view关联
	        searchView.setSearchableInfo(info); 
	    }
	}

    @Override  
    public boolean onMenuOpened(int featureId, Menu menu) {  
    	//显示菜单项左侧的图标
        Utils.setOverflowIconVisible(featureId, menu);  
        return super.onMenuOpened(featureId, menu);  
    }  
  
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.search, menu);
		//对搜索框做初始化
		initSearchView(menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		int id = item.getItemId();
		if (id == android.R.id.home) {
			finish();
		} else if (id == R.id.menu_about) {
			Toast.makeText(this, "这个是顶部导航栏的演示demo", Toast.LENGTH_LONG).show();
			return true;
		} else if (id == R.id.menu_quit) {
			finish();
		}
		return super.onOptionsItemSelected(item);
	}
}



下面是顶部导航栏三种方式的效果图
原生导航


定制导航


搜索导航



点击下载本文用到的顶部导航栏三种方式的代码



点此查看Android开发笔记的完整目录

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值