toolbar之menu高階用法
前言
在通用的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");