1. 程式人生 > >toolbar之menu高階用法

toolbar之menu高階用法

前言

在通用的menu使用中,通常的使用方式有以下兩類:

 

圖片形式選單和文字形式選單,但是這兩種形式並不能滿足所有需求,在實際專案中也可能需要同時需要使用圖片和文字,

如同下圖:

本文將以兩種形式介紹圖片+文字實現選單

 

  1. 自定義ActionProvider
  2. 通過ActionLayout定義選單佈局

先看效果:

 

  • 自定義ActionProvider

首先自定義CustomActionProvider繼承ActionProvider,因為Toolbar

support包下的,所以我們要用support下的ActionProvider類,這個類是在support.v4下,它是相容ToolbarActionBar;

 

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/ActionBarMenu的點選效果,

然後完善我們的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");
到此兩種方法介紹結束,原始碼下載地址 點選開啟連結