一、关于ActionBar的item:
1)动态修改item的title和icon:
有时候ActionBar上的Item需要根据某种状态来显示不同title和icon,比如一些收音机上ActionBar上有控制其是否外放的Item,就要根据收音机是否处于外放状态来显示不同的状态的titel和icon,甚至控制Item是显示还是被折叠。这个就要重写函数onPrepareOptionsMenu()来实现。eg:
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.findItem(R.id.action_settings)
.setIcon(R.drawable.ic_launcher)
.setTitle("复制")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
return super.onPrepareOptionsMenu(menu);
}
2)让overflow中的item显示图标:
通常看到的效果:overflow中的item只显示titel,并没有显示icon。为什么会这样?因为在源码中控制这个显示的变量默认为false。可以查看源码中MenuBuilder.java中的mOptionalIconsVisible。
默认mOptionalIconsVisible = false,而对mOptionalIconsVisible做处理的函数仅有:
void setOptionalIconsVisible(boolean visible){
mOptionalIconsVisible = visible;
}
居然有函数去设置mOptionalIconsVisible的值,为什么mOptionalIconsVisible的值始终是false。没错,猜的没错,函数setOptionalIconsVisible()没有地方调用,搜索整个Android工程源码,这个函数只处在MenuBuilder类中被定义,没被其他地方调用过,所以mOptionalIconsVisible依旧是默认值false,而我们也不能通过MenuBuilder类来调用这个函数。要将mOptionalIconsVisible的值变为true,就要通过JAVA的反射机制了。在onCreateOptionsMenu()方法中最前面调用下面方法:
private void setOptionalIconVisible(Menu menu)
{
try
{
Class<?> classname= Class.forName("com.android.internal.view.menu.MenuBuilder");
Method m = classname.getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
m.setAccessible(true);
m.invoke(menu, true);
} catch (Exception e)
{
e.printStackTrace();
}
}
如果调用这个方法以后还无效,就要看使用的activity是否用的ActionBarActivity,因为ActionBarActivity是support.v7里面的,MenuBuilder类的路径不同。具体代码如下:
private void setOptionalIconVisible(Menu menu)
{
try
{
Class<?> classname = Class.forName("android.support.v7.internal.view.menu.MenuBuilder");
Method m = classname.getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
m.setAccessible(true);
m.invoke(menu, true);
} catch (Exception e)
{
Log.i(TAG, "not found!");
e.printStackTrace();
}
}
看上面的图显示,终于Overflow里的action 的Icon 和 title同时显示了。然而要实现这种效果还有没有方法呢?还可以通过自定义Action 来实现:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
SubMenu subMenu = menu.addSubMenu("");
subMenu.add("搜索").setIcon(R.drawable.ic_launcher)
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return false;
}
});
subMenu.add("设置").setIcon(R.drawable.ic_launcher)
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return false;
}
});
MenuItem item = subMenu.getItem();
item.setIcon(R.drawable.abc_ic_menu_moreoverflow_mtrl_alpha);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return super.onCreateOptionsMenu(menu);
}
二、关于ActionBar上的分享Action:
在<Android-ActionBar>中已经提到过了ActionBar增加 分享provider,这里自定义一个分享provider。
写一个类继承于ShareActionProvider,并重写部分方法,主要的工作要把分享中原有的subMenu先clear掉,然后重新增加新的submenu,如:
import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.ShareActionProvider;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import android.view.View;
public class CustomShareActionProvider extends ShareActionProvider{
public CustomShareActionProvider(Context context) {
super(context);
}
@Override
public View onCreateActionView() {
return null;
}
@Override
public void onPrepareSubMenu(SubMenu subMenu) {
//最好先clear submenu,以防内存泄露什么的。
subMenu.clear();
subMenu.add("复制").setIcon(R.drawable.abc_ic_menu_copy_mtrl_am_alpha)
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return false;
}
});
subMenu.add(R.string.action_settings).setIcon(R.drawable.abc_ic_menu_cut_mtrl_alpha)
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return false;
}
});
}
@Override
public void setShareIntent(Intent arg0) {
super.setShareIntent(arg0);
}
}
自定义share provider以后,需要在对应的menu中适配分享item的actionProviderClass属性:
<item
android:id="@+id/action_share"
android:icon="@android:drawable/ic_menu_share"
android:title="分享"
app:showAsAction="ifRoom"
app:actionProviderClass="com.example.ActionBar.CustomShareActionProvider"/>
三、简要介绍下使用Split action bar:
如果你的activity运行在一个屏幕比较小的设备上,Split action bar 在屏幕的底部提供了一个独立的bar,用来显示所有的action Item。
要完成使用Split action bar 需要以下两步:
1)在清单文件中配置activity或者application的属性:
2)这项属性要求API-LEVEL最小为14,要支持比较旧的版本,需要配置<meta-data />属性:
<manifest ...> <activityuiOptions="splitActionBarWhenNarrow" ... > <meta-dataandroid:name="android.support.UI_OPTIONS" android:value="splitActionBarWhenNarrow"/> </activity> </manifest>
四、增加导航Tab:
![]()
要达到上面图中的效果,要做以下几步:
1)实现ActionBar.Tablistener接口(Android官方文档中提到这个已经过时,推荐考虑使用:http://developer.android.com/design/patterns/navigation.html):public class CustomTabListener<T extends Fragment> implements TabListener{ private Fragment mFragment; private final ActionBarActivity mActivity; private final String mTag; private final Class<T> mClass; public CustomTabListener(ActionBarActivity activity, String tag, Class<T> clz) { mActivity = activity; mTag = tag; mClass = clz; } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { // User selected the already selected tab. Usually do nothing. } //Tab被选择时调用 @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { // 检查Fragment是否已经被初始化 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); } } //当前Tab 没有被选择时调用。 @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { if (mFragment != null) { // Detach the fragment, because another one is being attached ft.detach(mFragment); } } }
2)有几个Tab,对应就要几个Fragment:
public class ArtistFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.artist_fragment, container, false); return view; } }
public class AlbumFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view =inflater.inflate(R.layout.album_fragment, container, false); return view; } }
3)给对应的activity中增加Tab:protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_msg); ActionBar actionBar = getSupportActionBar(); actionBar.setDefaultDisplayHomeAsUpEnabled(true); // 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.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); Tab tab = actionBar.newTab().setText(R.string.artist_tab_name) .setTabListener(new CustomTabListener<ArtistFragment>(this, "artist", ArtistFragment.class)); actionBar.addTab(tab); tab = actionBar.newTab().setText(R.string.album_tab_name) .setTabListener(new CustomTabListener<AlbumFragment>(this, "album", AlbumFragment.class)); actionBar.addTab(tab); }
需要注意的是:activity的onCreate方法中不需要setContentView() 来加载要显示UI,因为加了Tab以后,要显示的UI来自于两个已建立的Fragment.五、自定义ActionBar的style:
actionBarStyle:为actionbar 指定各种样式和属性。
actionbar默认style:widget.ActionBar或者Widget.Appcompat.ActionBar(使用了Appcompat.support.v7 library).支持的style包括:background:为actionbar定义一张背景图,如果非support.v7,可以是颜色值。例如:<item name="android:background">#008B8B</item>backgroundStacked:为actionbar Tabs指定背景。backgroundSplit:为Split action bar指定背景。actionButtonStyle:为action button指定样式资源,parent style可以指定为:widget.ActionButton或者,Widget.AppCompat.ActionButton.actionOverflowButtonStyle:为overflow action items 指定样式资源。parent style可以指定为:Widget.ActionButton.Overflow或者Widget.AppCompat.ActionButton.Overflow.displayOptions:指定一个或多个action bar显示选项,比如,是否显示程序的Logo,显示程序的title,又或者 action bar 的 up button 等。divider:为action item之间的分割指定资源。titleTextStyle:为actionbar的title指定样式资源。action items style:actionButtonStyle:为action button指定样式资源,parent style可以指定为:widget.ActionButton或者,Widget.AppCompat.ActionButton.
actionBarItemBackground:为action bar items背景指定资源,这资源也可能是state-list drawable,以显示不同的选择状态。itemBackground:为每个action bar overflow item的背景指定资源,这资源也可能是state-list drawable,以显示不同的选择状态。actionBarDivider:为action items 之间分割指定资源。actionMenuTextColor:为每个action item上显示的文本指定颜色资源。actionMenuTextAppearance:为每个action item上显示的文本指定样式资源。
actionBarWidgetTheme:为填充到action bar中的Widgets指定theme资源,如action views。
Navigation tabs style:
actionBarTabStyle:为action bar中的tab指定资源,parent style可以指定为:Widget.AppCompat.ActionBar.TabView或者Widget.ActionBar.TabView。
actionBarTabBarStyle:为navigation tabs之间的thin bar指定样式资源。
actionBarTabTextStyle:为navigation tabs上显示的文本指定样式资源。
样例:
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- the theme applied to the application or activity --> <style name="CustomActionBarTheme" parent="@style/Theme.AppCompat.Light"> <item name="android:actionBarStyle">@style/MyActionBar</item> <item name="android:actionBarTabTextStyle">@style/TabTextStyle</item> <item name="android:actionMenuTextColor">@color/actionbar_text</item> <!-- Support library compatibility --> <item name="actionBarStyle">@style/MyActionBar</item> <item name="actionBarTabTextStyle">@style/TabTextStyle</item> <item name="actionMenuTextColor">@color/actionbar_text</item> </style> <!-- general styles for the action bar --> <style name="MyActionBar" parent="@style/Widget.AppCompat.ActionBar"> <item name="android:titleTextStyle">@style/TitleTextStyle</item> <item name="android:background">@drawable/actionbar_background</item> <item name="android:backgroundStacked">@drawable/actionbar_background</item> <item name="android:backgroundSplit">@drawable/actionbar_background</item> <!-- Support library compatibility --> <item name="titleTextStyle">@style/TitleTextStyle</item> <item name="background">@drawable/actionbar_background</item> <item name="backgroundStacked">@drawable/actionbar_background</item> <item name="backgroundSplit">@drawable/actionbar_background</item> </style> <!-- action bar title text --> <style name="TitleTextStyle" parent="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"> <item name="android:textColor">@color/actionbar_text</item> </style> <!-- action bar tab text --> <style name="TabTextStyle" parent="@style/Widget.AppCompat.ActionBar.TabText"> <item name="android:textColor">@color/actionbar_text</item> </style> </resources>
上面的例子,来自于Android官方文档,例子包括了常用情况使用,还一种就是使用support library(eg:support.v7)。自定义actionbar的背景:<!-- Application theme. --> <style name="AppTheme" parent="AppBaseTheme"> <item name="android:actionBarStyle">@style/CustomActionBar</item> </style> <style name="CustomActionBar" parent="@android:style/Widget.Holo.Light.ActionBar"> <!-- the action bar background,don't include tab background --> <item name="android:background">#008B8B</item> </style>
![]()
自定义actionbar和tab的背景:
<style name="AppTheme" parent="AppBaseTheme"> <item name="android:actionBarStyle">@style/CustomActionBar</item> </style> <style name="CustomActionBar" parent="@android:style/Widget.Holo.Light.ActionBar"> <!-- the action bar background,don't include tab background --> <item name="android:background">#008B8B</item> <!-- the tab background --> <item name="android:backgroundStacked">#00868B</item> </style>