自学android有一定的时间了,由于自学的原因发现自己的知识很散,不够系统,因此想通过学习android官方文档和写博客的形式进行整理和总结,同时从中学到更多的知识。
由于本人是初学者的原因,难免会出现一些错误,希望大家谅解和指出。
本篇主要写的是对actionBar的解析
参考:
1.android官方文档,文档所在目录为sdk/docs/index.html
2(http://blog.csdn.net/guolin_blog/article/details/18234477#reply)
ActionBar用于确定用户的位置并提供用户操作和导航模式
1.App icon 应用的图标,通过设置可以添加一个返回图标
2.Action Button 相当于普通的Button,可以监听点击事件
3.Action overflow ,可以显示隐藏的action button
actionBar的三个部分体现了actionBar的关键功能
确定当前位置,突出重要的功能(如上图的搜索),导航和视图切换
1.创建一个Activity并继承AppCompatAcitvity(取代ActionBarActivity)
2.在AndroidManifest中,将对Activity的theme进行设置
android:theme="@style/Theme.AppCompat.Light"
一般情况下创建activity是继承Activity的,可以对theme进行如下设置
android:theme="@android:style/Theme.Holo.Light"
这时候运行项目,就可以看到actionBar了。
既然有添加actionBar当然就会有移除actionBar,移除的方式有两种
1.将theme设置为带有NoActionBar的样式即可
2.添加如下代码
// ActionBar actionBar=getSupportActionBar();
// actionBar.hide();
ActionBar actionBar=getActionBar();
actionBar.hide();
移除actionBar,实际上就是将其隐藏,因此可以通过show()的方式将actionBar再次显示出来。
所有的actionButton和action overflow里的item 都是在menu资源文件夹下的xml文件中定义的。
所以,我们需要创建一个xml文件
在新创建的文件中添加item
<menu xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_search"
android:icon="@drawable/ic_action_search"
android:title="@string/action_search"
android:actionViewClass="android.widget.SearchView"
android:showAsAction="ifRoom|collapseActionView"
tools:ignore="AppCompatResource"/>
<item android:id="@+id/action_setting"
android:title="@string/action_settings"
android:icon="@mipmap/ic_launcher"
android:showAsAction="never"
tools:ignore="AppCompatResource"/>
menu>
所添加的item是显示在action overflow里面还是显示在actionBar上,可以通过showAsAction来进行设置。
Always:总是显示在actionBar上
IfRoom:如果actionBar上的还有空间,则显示在actionBar
Never:只显示在action overflow内
withText:如果你的menu item支持同时显示title和icon时,设置withText,就会同时 显示title和icon,比如如果设置ifRoom时默认只显示icon,加上withText时就会同时 显示title和icon。
android:showAsAction="withText|ifRoom"
特别注意的是:如果item显示在action overflow内时,即使你设置了title和icon,也 只会显示title不会显示icon,因为不特别设置的话,action overflow不会显示图片。
CollapseActionView:会在下面举例介绍
创建完毕后,我们就需要在actionBar上添加我们的action,这时候我们需要重载onCreateOptionsMenu()方法。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater=getMenuInflater();
inflater.inflate(R.menu.action_bar_menu,menu);
return super.onCreateOptionsMenu(menu);
}
这样actionBar上就会出现我们在menu中定义的item,每个item可以被点击,但还缺少点击事件。
实现onOptionsItemSelected()方法给每个Item添加点击事件,与button实现点击方法类似。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId())
{
case R.id.action_search:
//....
return true;
case R.id.action_setting:
//....
return true;
default:
return super.onOptionsItemSelected(item);
}
}
一般来说上面的操作加下面的一些方法,基本上可以实现常见的actionBar了。
①去除icon
如果activity继承自Activity,添加以下代码通过选择true和false显示和隐藏icon。
getActionBar().setDisplayShowHomeEnabled(false);
如果activity继承AppCompatActivity,原本就不会显示icon,要显示Icon必须添加以下代码。
ActionBar actionBar=getSupportActionBar();
actionBar.setLogo(R.mipmap.ic_launcher);
actionBar.setDisplayUseLogoEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
②显示导航按钮
ActionBar actionBar=getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
通过上述代码我们会发现在actionBar上多了一个箭头,这时这部分就相当于一个按钮,可以被点击同时响应点击事件。
通常增加该按钮的目的是为了实现导航的功能,即实现页面的跳转。
当我们明确需要跳转的页面时可以通过以下代码来快速实现。
".SecondActivity"
android:parentActivityName=".MainActivity">//想要返回的activity
"android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />//想要返回的activity
在上述代码中我们明确在SecondActivity中点击导航按钮会返回到我们MainActivity中。
当然很多时候进入该activity的父activity是不确定的,因此我们可以重写getParentActivityIntent ()方法进行不同activity的跳转。
@Override
public Intent getParentActivityIntent() {
//常见的方式是通过获取getIntent传递过来的Intent中携带的数据
//根据该数据判断其对应的activity,之后创建新的intent指向该activity
return intent;
}
返回的Intent就是我们点击后会实现的意图。这里我没有给出具体的代码,只是给出了实现的逻辑。因为实现的方法每个人都不同,但都很简单。
在测试这段代码时,无意间我发现一个很奇怪的事情
@Override
public Intent getParentActivityIntent() {
Intent intent=new Intent();
intent.setComponent(new ComponentName("aa","aa"));
return intent;
}
通过setComponent,无论我填写的ComponentName的数据是什么,点击都能成功返回到上一个activity。一直搞不懂,求大牛说明下原因。
由于导航按钮也是actionBar上的一个item,所以我们也可以在onOptionsItemSelected()中实现它的点击事件。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId())
{
case android.R.id.home://对应的Id
//点击后要实现的代码
return true;
default:
return super.onOptionsItemSelected(item);
}
}
③在overflow中显示Icon
在上面提到overflow中默认是不显示Icon的,我们可以通过以下方法显示icon
rivate void setOverflowIconVisiable(Menu menu)//通过反射机制
{
if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
try {
Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
m.setAccessible(true);
m.invoke(menu, true);
} catch (Exception e) {
}
}
}
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
if (menu!=null)
{
setOverflowIconVisiable(menu);
}
return super.onMenuOpened(featureId, menu);
}
一个ActionView是一个组件,用来替换ActionBar中的actionButton,可以在不用切换Activity和 Fragment并且不更换actionBar的情况下实现一些丰富的功能。
直接上例子
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_search"
android:icon="@drawable/ic_action_search"
android:title="@string/action_search" android:actionViewClass="android.support.v7.widget.SearchView"
android:showAsAction="ifRoom|collapseActionView"/>
<item android:id="@+id/action_setting"
android:title="@string/action_settings"
android:icon="@mipmap/ic_launcher"
android:showAsAction="never"/>
menu>
在showAsAction中添加collapseActionView选项
collapseActionView:通常与ifRoom一起使用,只会在设置了actionViewClass才会生效,它的作用是将actionViewClass设置的actionView折叠进actionButton中,当我们点击该actionButton时会将actionView展开
actionViewClass:指定一个组件作为actionView
例子中添加的是一个SearchView,当然我们也可以添加一个Button
android:actionViewClass="android.widget.Button"
注意:当我们将一个actionView折叠进一个actionButton中,我们就不需要对该actionButton实现点击事件,即我们在onOptionsItemSelected()中不该对actionButton进行响应,这是因为当我们点击actionButton时,系统依然会调用onOptionsItemSelected()。
成功在actionBar上显示了actionView,我们就需要响应事件
//从menu中获取search的Item
MenuItem searchItem=menu.findItem(R.id.action_search);
//再从Item中获取view
SearchView searchView= (SearchView)searchItem.getActionView();
//得到view对象,之后想干什么就能干什么了
另外Android还实现了对actionView折叠和展开的监听
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater=getMenuInflater();
inflater.inflate(R.menu.action_bar_menu,menu);
//从menu中获取search的Item
MenuItem searchItem=menu.findItem(R.id.action_search);
MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item)
{
return true;//true,展开actionView
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item)
{
return true;//true,折叠actionView
}
});
return super.onCreateOptionsMenu(menu);
}
与actionView类似,actionProvider用一个自定义的layout来代替actionButton,不同于actionView的是,actionProvider控制所有的action的行为并且当我们点击actionProvider会弹出子菜单。
我们可以通过继承ActionProvider类来自定义一个actionProvider。也可以使用android本身个给我们提供的一些actionProvider例如ShareActionProvider(实现分享)。
item android:id="@+id/action_share"
android:title="@string/share"
android:showAsAction="ifRoom"
tools:ignore="AppCompatResource" android:actionProviderClass="android.widget.ShareActionProvider"
/>
这时我们运行程序会发现多了个分享的button,当我们点击会发现并没有出现子菜单,这是因为我们还没定义子菜单中显示的内容。
在onCreateOptionMenu()中添加如下代码
MenuItem shareItem = menu.findItem(R.id.action_share);
ShareActionProvider mShareActionProvider = (ShareActionProvider)shareItem.getActionProvider();
mShareActionProvider.setShareIntent(getDefaultIntent());
private Intent getDefaultIntent() {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/*");
return intent;
}
当我们点击子菜单中的Item后,会跳转到相应的界面。
除了使用ShareActionProvider之外,我们当然也可以自定义一个Action Provider,实现我们想要的功能。
public class MyActionProvider extends ActionProvider{
private Context mContext;
public MyActionProvider(Context context) {
super(context);
this.mContext=context;
}
@Override
public View onCreateActionView() {
LayoutInflater inflater=LayoutInflater.from(mContext);
View view=inflater.inflate(R.layout.action_provider, null);
Button btn= (Button) view.findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext,
"click",Toast.LENGTH_SHORT).show();
}
});
return view;
}
}
发现actionbar上多了一个按钮,当我们点击的该button时,发现并没有像ShareActionProvider一样弹出一个子菜单(这时候跟actionButton的作用很像)。
想要实现子菜单的弹出,可以这样写
@Override
public View onCreateActionView() {
return null;//必须返回一个null,不然不会弹出子菜单
}
//必须重写该方法并返回true
@Override
public boolean hasSubMenu() {
return true;
}
@Override
public void onPrepareSubMenu(SubMenu subMenu) {
subMenu.clear();
subMenu.add(0, 0, 0, "menu1")
.setIcon(R.mipmap.ic_launcher)
.setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
Toast.makeText(mContext, "submenu1", Toast.LENGTH_SHORT).show();
return true;
}
});
subMenu.add(0, 1, 1,"menu2")
.setIcon(R.mipmap.ic_launcher)
.setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
Toast.makeText(mContext, "submenu", Toast.LENGTH_SHORT).show();
return true;
}
});
}
至此,我们可以成功的实现一个完整的actionBar,当然actionBar还提供了Tab导航和下拉式导航,这里就不叙述了(主要是我没用过,也没看见哪个app有用过,现在导航好像都是通过viewPager实现的,有需要的可以看官方文档)
提示:在写代码的时候,千万不能导错包
通过上面的方法创建的actionBar太过单一,我们也可以通过自定义actionBar,来实现我们想要的actionBar的样式
自定义actionBar的方式有很多,android本身提供了两种基本的activity主题。
Theme.Holo :一种”dark”的主题
Theme.Holo.Light:一种”light”的主题
我们也可以通过改变各种参数,实现不同的风格
actionBarStyle:
Baskground:设置actionBar的背景
<style name="MyActionBarStyle" parent="@android:style/Widget.Holo.Light.ActionBar">
<item name="android:background">@color/orange
style>
ActionButtonStyle:设置actionButtonStyle的样式
<style name="MyActionButtonStyle"parent="@android:style/Widget.ActionButton">
<item name="android:background">@color/green
style>
ActionOverflowButtonStyle:设置actionOverflowButtonStyle的样式
<style name="MyActionBarStyleOverflow" parent="@android:style/Widget.ActionButton.Overflow">
<item name="android:src">@mipmap/ic_launcher
style>
TitleTextStyle:actionBar title的样式
这里我只是举了几个例子,关于样式的自定义还有很多,有兴趣的可以查询官方文档。
好了,到了这里关于actionBar的解析也就到了这里,当然本人水平,有限里面的内容绝大部分来源于android的官方文档,当然其中也有自己的一些理解。
在上面的内容中有一小部分内容也是第一次接触到,可能写的不是很准确,欢迎大家指出错误。
第一次写博客,花了很多时间,从中也收获了很多,希望自己能一直坚持下去(第一次多英文文档,有点痛苦,不过看着看着就习惯了,算是一种进步吧)