Android ActionBar总结二
来源:互联网 发布:淘宝搜索流量下降 编辑:程序博客网 时间:2024/06/18 13:45
转载请注明 http://blog.csdn.net/sinat_30276961/article/details/48031057
上一篇Android ActionBar总结一介绍了Actionbar的基本用法,这一篇承接上篇,继续讲述ActionBar更多功能。
Action Item
对于每个action item,如果你既要显示图标又要显示文字,那就这样定义:
<item yourapp:showAsAction="ifRoom|withText" ... />
我们再看下每个item的定义方式:
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:yourapp="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/action_search" android:icon="@drawable/ic_action_search" android:title="@string/action_search" yourapp:showAsAction="ifRoom" /> ...</menu>
这里,有一点必须注意的是,android:title这个属性必须要定义。原因有这些:
1.当如果action item放不下了,它会自动移动到右边的overflow里,那里显示方式是只显示title。
2.长按某个action item,会触发显示title。
还有一点需要注意的是:
如果是这种情况,你关联action item和menu是在fragment里,使用的是fragment的onCreateOptionsMenu(),然后点击某个action item时的回调顺序是:
activity.onOptionsItemSelected() –> fragment.onOptionsItemSelected()。
所以,如果你在activity里复写了onOptionsItemSelected,记得调用下return super.onOptionsItemSelected(item);这样才会进入fragment的onOptionsItemSelected。
使用split action bar
split action bar,顾名思义是分离的actionbar。它的作用就是在窄屏的情况下,分离部分actionbar到屏幕底端,从而可以显示全部的action item。
如下图:
使用方式也很简单,对于support v7使用者只要两步:
1.manifest里的activity定义uiOptions=”splitActionBarWhenNarrow”
2.调用v7库需要使用meta-data元素
<manifest ...> <activity uiOptions="splitActionBarWhenNarrow" ... > <meta-data android:name="android.support.UI_OPTIONS" android:value="splitActionBarWhenNarrow" /> </activity></manifest>
就像图中第三个手机显示的情况,对于action tab,可以通过设置setDisplayShowHomeEnabled(false)和setDisplayShowTitleEnabled(false),把title和icon显示去掉,然后再设置split属性,就OK了。
通过图标回退
如上图展示的,在图标的左边有个小箭头,那个就意味着图标回退功能已经打开。
我们可以通过setDisplayHomeAsUpEnabled()来打开这个功能。
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_details); ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); ...}
打开这个功能之后,我们有两种方式可以设置其点击之后的反馈:
1.在manifest里指定parent activity。
这种情况一般针对该activity确定永远返回到某个上层的activity。
定义方式很简单,可参考如下代码:
<application ... > ... <!-- The main/home activity (has no parent activity) --> <activity android:name="com.example.myfirstapp.MainActivity" ...> ... </activity> <!-- A child of the main activity --> <activity android:name="com.example.myfirstapp.DisplayMessageActivity" android:label="@string/title_activity_display_message" android:parentActivityName="com.example.myfirstapp.MainActivity" > <!-- Parent activity meta-data to support API level 7+ --> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.example.myfirstapp.MainActivity" /> </activity></application>
2.通过复写getSupportParentActivityIntent()和onCreateSupportNavigateUpTaskStack()
这种情况一般针对该activity有可能返回到不同的上层activity,这样一来,就不要在manifest定义parent activity。只能通过复写上面的方法,自己控制了。
那上面的两个复写方法系统调用情况怎么安排呢?
getSupportParentActivityIntent(),当前的activity在自己app的task里的话,系统会调用该方法。然后你可以自己创建个intent,设置好flag,然后自己选择返回到的堆栈里的某个activity。
onCreateSupportNavigateUpTaskStack(),当前的activity不在该app的task里的话,系统会调用该方法。然后要使用TaskStackBuilder构造合适的back stack。
要注意的是:
如果你构建的界面层级关系是通过fragment构建的,那么上述方案就不可行了。在这种情况下,你应该复写onSupportNavigateUp()来执行合适的fragment事务。一般通过调用popBackStack()来回退。
增加Action view
Action View是用来扩展action item的,它可以在不替换actionbar的情况下,展示其他action item。
如下图所示:
要定义action view,你可以使用布局文件或者是一个自定义控件。上图第一个展示的布局形式的,第二个展示的是自定义view形式的。
怎么使用呢?
1.需要在menu xml文件里定义:
<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:yourapp="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/action_search" android:title="@string/action_search" android:icon="@drawable/ic_action_search" yourapp:showAsAction="ifRoom|collapseActionView" yourapp:actionViewClass="android.support.v7.widget.SearchView" /></menu>
这里的showAsAction要多加个collapseActionView属性,然后是定义actionLayout或者actionViewClass这两个属性。
如果你要添加一些监听事件,对于布局形式的,在onCreateOptionsMenu()进行操作。
你要先获得对应的MenuItem,然后通过MenuItemCompat.getActionView()获得ActionView。
@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_next, menu); final MenuItem editItem = menu.findItem(R.id.action_edit); View editView = MenuItemCompat.getActionView(editItem); TextView title = (TextView) editView.findViewById(R.id.title); title.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(NextActivity.this, "Click Title", Toast.LENGTH_SHORT).show(); } }); ImageView imgEdit = (ImageView) editView.findViewById(R.id.img_edit); imgEdit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(NextActivity.this, "Click Edit Icon", Toast.LENGTH_SHORT).show(); // 销毁actionview MenuItemCompat.collapseActionView(editItem); } }); MenuItemCompat.setOnActionExpandListener(editItem, new MenuItemCompat.OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { Toast.makeText(NextActivity.this, "Edit ActionView expand", Toast.LENGTH_SHORT).show(); return true; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { Toast.makeText(NextActivity.this, "Edit ActionView collapse", Toast.LENGTH_SHORT).show(); return true; } }); final MenuItem searchItem = menu.findItem(R.id.action_refresh); SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem); return true; }
如果是3.0以上的直接使用actionbar的,通过如下方式获得ActionView:
menu.findItem(R.id.action_search).getActionView()
可以通过MenuItemCompat.setOnActionExpandListener监听actionview的展开和销毁。注意,那里复写的onMenuItemActionCollapse和onMenuItemActionExpand两个方法里必须返回true,否则不会有效果。
增加Action provider
Action Provider和Action View其实很类似,唯一的区别应该是Action Provider不能用布局去定义,但是可以展示子菜单。
在menu xml里定义的方式很简单,通过actionProviderClass定义actionprovider,不需要在onOptionsItemSelected做任何操作,因为它的交互都定义在其内部。如果你非要有其他交互,最后要返回false,这样,actionprovider才能工作。
使用ShareActionProvider
对于常规的应用,传递数据给其他应用是很常见的。ShareActionProvider给我们提供了这样的功能。如下是其定义:
<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:yourapp="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/action_share" android:title="@string/share" yourapp:showAsAction="ifRoom" yourapp:actionProviderClass="android.support.v7.widget.ShareActionProvider" /> ...</menu>
这样一来,ShareActionProvider已经定义好了,现在需要做的是,给它一个intent,让它去展示符合这个intent的应用列表。
private ShareActionProvider mShareActionProvider;@Overridepublic boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main_activity_actions, menu); // Set up ShareActionProvider's default share intent MenuItem shareItem = menu.findItem(R.id.action_share); mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem); mShareActionProvider.setShareIntent(getDefaultIntent()); return super.onCreateOptionsMenu(menu);}/** Defines a default (dummy) share intent to initialize the action provider. * However, as soon as the actual content to be used in the intent * is known or changes, you must update the share intent by again calling * mShareActionProvider.setShareIntent() */private Intent getDefaultIntent() { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("image/*"); return intent;}
如上代码,通过MenuItemCompat.getActionProvider获取到ActionProvider。然后通过ShareActionProvider.setShareIntent(),给它一个intent。这部分在onCreateOptionsMenu里定义。
ShareActionProvider自己有管理一个记录,记录各个应用的使用情况,然后按使用频繁程度,从上到下排列出来。这部分做个了解就行。
自定义Action Provider
自定义action provider的好处是,封装了事件监听和反馈,这样可以不用每次在各个activity或者fragment里写相同的事件响应代码,复用性就体现出来了。
我们通过继承ActionProvider,然后实现它的回调方法就行。
public class MyActionProvider extends ActionProvider{ Context mContext; /** * Creates a new instance. * * @param context Context for accessing resources. */ public MyActionProvider(Context context) { super(context); mContext = context; } @Override public View onCreateActionView() { LayoutInflater layoutInflater = LayoutInflater.from(mContext); View view = layoutInflater.inflate(R.layout.action_provider_layout, null); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent1 = new Intent(mContext, MyActivity.class); mContext.startActivity(intent1); } }); return view; }}
从上面可以看到,你必须实现两个方法。
1.构造函数,可以传context进去
2.onCreateActionView,用于返回给actionbar来显示。
增加导航tabs
Actionbar整合tab引导键的显示,横屏时可以显示在actionbar,竖屏时,如果显示不下,就分开显示。
它的定义方式很简单。
你首先需要准备一个或多个fragment,用来展示内容。你可以使用自己的布局文件,比方说activity_main,在里面定义一个fragment的容器。如果你要展示的内容充满整个activity,其实可以不用布局文件,也就是说可以不用调用setContentView()。直接使用系统给的framelayout。
这里插一句好了,我们定义的布局文件其实是放到系统设置的布局文件的framelayout里。
通过android.R.id.content获取到那个framelayout。
决定好你内容的展示,接着分两步定义:
1.实现ActionBar.TabListener这个接口,这个接口主要是回调tab选中没选中情况。
2.每个tab通过实例化ActionBar.Tab,然后给它设置ActionBar.TabListener,最后actionbar.addTab
要注意的是ActionBar.TabListener的回调函数里,返回的不是哪个fragment被选中或没选中,而是返回ActionBar.Tab。你必须自己关联各个ActionBar.Tab和fragment。
比方说如下代码:
public static class TabListener<T extends Fragment> implements ActionBar.TabListener { private Fragment mFragment; private final Activity mActivity; private final String mTag; private final Class<T> mClass; /** Constructor used each time a new tab is created. * @param activity The host Activity, used to instantiate the fragment * @param tag The identifier tag for the fragment * @param clz The fragment's Class, used to instantiate the fragment */ public TabListener(Activity activity, String tag, Class<T> clz) { mActivity = activity; mTag = tag; mClass = clz; } /* The following are each of the ActionBar.TabListener callbacks */ public void onTabSelected(Tab tab, FragmentTransaction ft) { // Check if the fragment is already initialized if (mFragment == null) { // If not, instantiate and add it to the activity mFragment = Fragment.instantiate(mActivity, mClass.getName()); ft.add(android.R.id.content, mFragment, mTag); } else { // If it exists, simply attach it in order to show it ft.attach(mFragment); } } public void onTabUnselected(Tab tab, FragmentTransaction ft) { if (mFragment != null) { // Detach the fragment, because another one is being attached ft.detach(mFragment); } } public void onTabReselected(Tab tab, FragmentTransaction ft) { // User selected the already selected tab. Usually do nothing. }}
这里需要注意的是FragmentTransaction执行完之后,我们不需要添加commit(),系统会帮我们调用。同时,你也不能自己去添加fragment到back stack。
接下去,就只剩下创建每个ActionBar.Tab,然后添加到actionbar。同时,你必须设置一下模式setNavigationMode(NAVIGATION_MODE_TABS):
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Notice that setContentView() is not used, because we use the root // android.R.id.content as the container for each fragment // setup action bar for tabs ActionBar actionBar = getSupportActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); actionBar.setDisplayShowTitleEnabled(false); Tab tab = actionBar.newTab() .setText(R.string.artist) .setTabListener(new TabListener<ArtistFragment>( this, "artist", ArtistFragment.class)); actionBar.addTab(tab); tab = actionBar.newTab() .setText(R.string.album) .setTabListener(new TabListener<AlbumFragment>( this, "album", AlbumFragment.class)); actionBar.addTab(tab);}
如果你要支持横竖屏切换,又要保存当前选择tab的情况,那就复写onSaveInstanceState,可以复写activity的那个,然后在里面通过getSelectedNavigationIndex()获取到当前选择的position。
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); int selectItem = getSupportActionBar().getSelectedNavigationIndex(); outState.putInt("select_item", selectItem); }
然后在onCreate()再读取一下。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); int selectItem = 0; if (savedInstanceState != null) { selectItem = savedInstanceState.getInt("select_item"); } ...... actionBar.setSelectedNavigationItem(selectItem); }
对于fragment的操作,保存state是很重要的,这样会给用户更好接受。
上述例子是用ActionBar.TabListener来控制fragment,还有一种,可以通过viewpager来控制。这里就点一下,等总结fragment再去讲。
添加drop-down菜单
Actionbar还提供了下拉式的导航菜单,它是由spinner来实现的,并维持在Actionbar内部,我们不需要去管理细节,只需要给它值和布局就可以。
一般在这种场合可以使用下拉式菜单,当年需要偶尔使用切换功能,但不经常使用。如果是经常使用的情况,那最好选择tab形式的导航菜单。
那怎么实现该功能呢?大体上,只要四步,就可以实现drop-down list。
1.创建一个SpinnerAdapter,给它绑定数据和布局文件。
2.实现ActionBar.OnNavigationListener接口,用来监听选择事件。
3.在Activity的onCreate()阶段,设置Actionbar的模式为list模式。
setNavigationMode(NAVIGATION_MODE_LIST).
4.关联spinnerAdapter和listener。如下所示:
actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback);
怎么样,很简单吧。
如果要查看代码,可以滚动到最后,那里会提供源码。
让Actionbar多样式
如果你不想让你的Actionbar总是那么千篇一律,毫无性格,毫无特点,那该怎么办?别着急,系统给我们提供了改变它外貌的办法,那就是通过自定它的主题和样式,然后把想要改变的属性增加改变就行。
常规外观
actionBarStyle
Actionbar的样式资源,里面定义了一堆关于actionbar样式的属性。
它的默认样式是Widget.AppCompat.ActionBar,也就是说,如果我们要复写actionbar的样式,就要继承它,这样你就不需要重新去定义大量的属性。
我们来看看它的常规属性:
1.background
这个大家最熟悉了。
2.backgroundStacked
actionbar上的tab背景。
3.backgroundSplit
actionbar分离到底部的背景。
4.actionButtonStyle
actionbar上button的样式资源,默认是Widget.AppCompat.ActionButton,你如果要复写,就要继承这个。
5.actionOverflowButtonStyle
actionbar上超出部分的按键样式资源(overflow),就是右边那三个点。
默认是Widget.AppCompat.ActionButton.Overflow,同样,要复写的话,继承该默认样式。
6.displayOptions
定义actionbar显示的属性,比方说是否使用logo,是否显示左边的返回键等等。
7.divider
定义每个action item之间的分隔图型
8.titleTextStyle
actionbar的title样式资源,默认是TextAppearance.AppCompat.Widget.ActionBar.Title。
windowActionBarOverlay
这个在上一篇有讲过,这里再带过一下。它是定义actionbar是否覆盖在activity上。如果涉及到需要频繁显示和隐藏actionbar,可以选择开启overlay模式。
Demo源码入口
- Android ActionBar总结二
- Android ActionBar详解(二)
- Android之ActionBar(二)
- Android ActionBar总结一
- Android ActionBar 使用总结
- Android ActionBar学习(二) -- 自定义ActionBar Style
- Android ActionBar学习(二) -- 自定义ActionBar Style
- Android ActionBar使用方法(二)
- Android ActionBar使用方法(二)
- Android ActionBar使用方法(二)
- ActionBar之属性详解总结(二)
- ActionBar使用方法 - Android活动栏(二)
- Android轩辕剑之ActionBar之二
- Android 学习笔记二十三之 ActionBar
- Android ActionBar的源代码分析(二)
- Android活动条(actionbar)使用详解(二)
- ActionBar使用方法 - Android活动栏(二)
- Toolbar 替换ActionBar(android MD 二)
- android 记录一下自己的微信支付
- Java并发编程:线程池的使用
- JSP文件保存的编码与页面中的pageEncoding和contentType之间的关系
- mysql琐碎知识点
- 正则表达式之掌握grep的用法
- Android ActionBar总结二
- 简单错误记录(华为16年研发试题)
- 开始Spring Cloud Config
- Ngui如何弹出提示消息,并淡出【支持多条】
- android md5加密和sha-1加密方法
- 百分比进度框
- Python计算矩阵相乘
- JAVA问题总结之17-杨辉三角的实现
- POJ2187---Beauty Contest