前言
在通用的menu使用中,通常的使用方式有以下两类:
图片形式菜单和文字形式菜单,但是这两种形式并不能满足所有需求,在实际项目中也可能需要同时需要使用图片和文字,
如同下图:
本文将以两种形式介绍图片+文字实现菜单
- 自定义ActionProvider
- 通过ActionLayout定义菜单布局
先看效果:
- 自定义ActionProvider
首先自定义CustomActionProvider继承ActionProvider,因为
Toolbar
是support
包下的,所以我们要用support
下的ActionProvider
类,这个类是在support.v4
下,它是兼容Toolbar
和ActionBar
;
public class CustomActionProvider extends ActionProvider { public CustomActionProvider(Context context) { super(context); } @Override public View onCreateActionView() { return view; } }
这里需要定义一个显示的view
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="match_parent" android:background="?actionBarItemBackground" android:gravity="center" android:orientation="horizontal"> <ImageView android:id="@+id/iv_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/filter" /> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:textColor="@android:color/white" /> </LinearLayout>
特别说明一下,
android:background="?actionBarItemBackground"
是引用系统默认
Toolbar
/ActionBar
的Menu
的点击效果,
然后完善我们的CustomActionProvider,
public class CustomActionProvider extends ActionProvider { public CustomActionProvider(Context context) { super(context); } TextView mTitle; ImageView mIcon; @Override public View onCreateActionView() { //读取support下Toolbar/ActionBar的高度,为了让这个Menu高和宽和系统的menu达到一致 int size = getContext().getResources().getDimensionPixelSize( android.support.design.R.dimen.abc_action_bar_default_height_material); ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(size, size); View view = LayoutInflater.from(getContext()) .inflate(R.layout.layout_menu_provider, null, false); view.setLayoutParams(layoutParams); mTitle = view.findViewById(R.id.tv_title); mIcon = view.findViewById(R.id.iv_image); view.setOnClickListener(mOnClickListener); return view; } View.OnClickListener mOnClickListener; public void setOnClickListener(View.OnClickListener onClickListener) { this.mOnClickListener = onClickListener; } }
添加自定义方法,供外部调用:
到这里,准备工作完成,然后是如何使用:public void setIcon(@DrawableRes int resId) { mIcon.setImageResource(resId); } public void setText(@StringRes int resId) { mTitle.setText(resId); } public void setText(CharSequence text) { mTitle.setText(text); }
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menu1" android:title="@string/menutext1" app:actionProviderClass="com.banzhi.toolbardemo.CustomActionProvider" app:showAsAction="always" /> </menu>
这里需要说明的是我们引用的app:actionProviderClass="com.banzhi.toolbardemo.CustomActionProvider"是以app开头,而不是android.然后是java代码:
CustomActionProvider actionProvider; @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_custom, menu); final MenuItem menuItem = menu.findItem(R.id.menu1); actionProvider = (CustomActionProvider) MenuItemCompat.getActionProvider(menuItem); actionProvider.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onOptionsItemSelected(menuItem); } }); return super.onCreateOptionsMenu(menu); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); actionProvider.setIcon(R.drawable.filter); actionProvider.setText(R.string.menutext1); } }
特别说明一点我们CustomActionProvider中暴露的方法不能再onCreateOptionMenu中直接调用,应为ActionProvider还没有加载完成,我这里是在onWindowFocusChanged()中调用。到此我们的第一种方式介绍结束,如果有不明白的地方,可以参考严大的博客点击打开链接。
- ActionLayout定义菜单布局
第二种方式比较简单,也不需要定义actionProvider,只需要定义一个布局文件:
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/text" android:background="?actionBarItemBackground" android:drawableLeft="@drawable/filter" android:drawablePadding="6dp" android:gravity="center" android:padding="6dp" android:text="@string/menutext2" android:textColor="@android:color/white"> </TextView>
然后在menu中使用
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menu2" android:title="@string/menutext2" app:actionLayout="@layout/custom_menu" app:showAsAction="always" /> </menu>
与自定义CustomActionProvider相同,这里也是使用app开头,而不是android,接着是java代码:
View actionView; MenuItem item; @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_custom, menu); item = menu.findItem(R.id.menu2); actionView = item.getActionView(); return super.onCreateOptionsMenu(menu); }
然后是添加点击事件:
@Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); actionView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { onOptionsItemSelected(item); } }); }
如果不添加点击事件,onOptionsItemSelected()中是不会有事件响应;为什么要在onWindowFocusChanged()中添加事件的原因与上面相同,这里就不在解释。如果需要修改menu文字或者图片,可以通过ActionView获取控件修改,比如:
到此两种方法介绍结束,源码下载地址 点击打开链接TextView text = actionView.findViewById(R.id.text); text.setText("filter");