Toolbar、ActionMenuView

作者: 草帽团长 | 来源:发表于2018-01-11 13:03 被阅读798次

    一、隐藏ActionBar方式


    1. 代码中隐藏

    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // 一定要在setContentView()之前调用
            supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main);
        }
    

    2. styles.xml文件中隐藏

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        ......
        <!-- 添加windowActionBar和windowNoTitle属性,单独添加windowActionBar会报错 -->
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
    
    <!-- 使用无标题栏主题 -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
           ......
    </style>
    

    二、Toolbar


    1. 简介

    ToolBar是Android 5.0推出的一个新的导航控件用于取代之前的ActionBar,高度可定制、灵活、具有Material Design风格,为了兼容低版本,该控件放在v7包中。

    2. 基本使用

    1. app.build添加v7依赖

    compile 'com.android.support:appcompat-v7:25.3.1'
    

    2. xml引用

    <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            app:title="MainActivity"
            app:titleTextColor="#ffffff"
            android:background="@color/colorPrimary">
    </android.support.v7.widget.Toolbar>
    

    注意:如果不设置 app:title属性,默认使用 manifest 文件中 <activity> 标签的 android:label 属性值作为标题内容,如果没有则使用<application>标签下的

    3. 代码设置Toolbar替换ActionBar

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    
    image
    image

    Toolbar还可以在xml或代码中设置很多属性,大部分感觉用处不大,常用的也就是一个NavigationIcon和Option Menu

    3. 要点

    1. NavigationIcon

    一般就是个返回按钮,或者是菜单按钮,使用如下:

    1.代码设置显示

     getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    
    image

    2.自定义按钮

    <android.support.v7.widget.Toolbar
    ......
     app:navigationIcon="@drawable/arrow_left">
     </android.support.v7.widget.Toolbar>
    

    toolbar.setNavigationIcon(R.drawable.arrow_left);
    

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setHomeAsUpIndicator(R.drawable.arrow_left);
    
    image

    3.点击事件

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                Toast.makeText(this, "返回", Toast.LENGTH_SHORT).show();
                break;
        }
        return true;
    }
    

    toolbar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(MainActivity.this, "返回", Toast.LENGTH_SHORT).show();
        }
    });
    

    2. Toolbar Shadow

    toolbar和主页面之间的分隔阴影

    1.创建xml,渐变阴影

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
           android:shape="rectangle">
        <gradient
            android:startColor="@android:color/transparent"
            android:endColor="#32000000"
            android:angle="90" />
    </shape>
    

    2.Toolbar下面使用

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World"
            android:textSize="18sp"/>
        <View
            android:layout_width="match_parent"
            android:layout_height="10dp"
            android:background="@drawable/shadow"/>
    </FrameLayout>
    

    效果


    image

    如果在Toolbar外面包一层AppbarLayout,自带阴影分隔线

    3. Toolbar标题居中

    1.定制标题,添加textview

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?actionBarSize"
        android:background="@color/colorPrimary"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="MainActivity"
            android:textSize="18sp"
            android:textColor="@android:color/white"
            android:textStyle="bold"
            android:layout_gravity="center"/>
            .....
    </android.support.v7.widget.Toolbar>
    

    2.隐藏Actionbar原标题

    // xml中设置 app:title="",无效
    toolbar.setTitle("");
    

    getSupportActionBar().setDisplayShowTitleEnabled(false);
    

    效果


    image

    4. Option Menu

    1.创建 menu目录,并创建相应menu xml文件

    <?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/menu_menu"
            android:icon="@drawable/ic_info"
            android:title="menu"
            app:showAsAction="collapseActionView"/>
        <item
            android:id="@+id/menu_home"
            android:icon="@drawable/ic_main"
            android:title="home"
            app:showAsAction="collapseActionView"/>
        <item
            android:id="@+id/menu_self"
            android:icon="@drawable/ic_me"
            android:title="self"
            app:showAsAction="collapseActionView"/>
    </menu>
    

    2.代码为toolbar添加menu,并设置点击事件

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu,menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.menu_menu:
                Toast.makeText(this, "菜单", Toast.LENGTH_SHORT).show();
                break;
            case R.id.menu_home:
                Toast.makeText(this, "首页", Toast.LENGTH_SHORT).show();
                break;
            case R.id.menu_self:
                Toast.makeText(this, "个人中心", Toast.LENGTH_SHORT).show();
                break;
        }
        return true;
    }
    

    效果


    image
    image

    3.相关问题

    3.1 想把菜单按钮的三个点变成白色

    在style中添加textColorSecondary属性,可将白点变为白色

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        ......
        <item name="android:textColorSecondary">#ffffff</item>
    </style>
    

    给toolbar设置theme属性和popupTheme属性

    <android.support.v7.widget.Toolbar
        .....
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
    

    如果只设置了theme属性,弹出菜单会变为黑底白字


    image

    注意:设置toolbar的theme为Dark暗色系ThemeOverlay.AppCompat.Dark,三个点的颜色不是特别白,有点暗,设置为ThemeOverlay.AppCompat.Dark.ActionBar,三个点为纯白色。

    [图片上传失败...(image-d7f746-1545206791836)]


    image

    可以看出,不管是theme(设置自己使用的主题)还是popupTheme(自己弹窗所用的主题),如果设置的是Light这种明亮主题(背景),那么它上面的元素则是呈现黑色;如果设置的是Dark这种暗色主题(背景),那么它上面的元素则是白色

    3.2 弹出菜单会覆盖toolbar

    设置弹窗所用的popupTheme中的overlapAnchor属性

    <style name="AppTheme.ToolbarPopupTheme" >
            <!-- 设置Menu窗口不覆盖Toolbar视图 -->
            <item name="overlapAnchor">false</item>
    </style>
    
     <android.support.v7.widget.Toolbar
            .....
            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/AppTheme.ToolbarPopupTheme"/>
    

    效果


    image

    3.3 弹窗中,为menuItem设置的图片没有显示,这个是4.0后源码改动的原因,解决方法是在activity中重写一个方法

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if(menu != null){
            if(menu.getClass().getSimpleName().equals("MenuBuilder")){
                try{
                    Method m = menu.getClass().getDeclaredMethod(
                            "setOptionalIconsVisible", Boolean.TYPE);
                    m.setAccessible(true);
                    m.invoke(menu, true);
                }
                catch(NoSuchMethodException e){}
                catch(Exception e){}
            }
        }
        return super.onPrepareOptionsMenu(menu);
    }
    
    

    效果


    image

    3.4 如果menuItem点击没有点击效果,或想设置字体颜色

    <style name="AppTheme.ToolbarPopupTheme" >
        <!-- 设置Menu菜单的背景色,这里是个选择器,按下背景置灰 -->
        <item name="android:itemBackground">@drawable/item_pressed_selector</item>
        <!-- 设置Menu菜单的字体颜色 -->
        <item name="android:textColorPrimary">@android:color/black</item>
        <!-- 设置Menu窗口不覆盖Toolbar视图 -->
        <item name="overlapAnchor">false</item>
    </style>
    

    三、ActionMenuView


    1. 简介

    Toolbar 默认将 Menu 内容显示在右边,ActionMenuView 是将原本位于 Toolbar 或者 ActionBar 中的 Menu 内容移到自己的名下,以 ViewGroup 的姿态将一系列的 Menu Item 囊括其中,再将自己搁置于 Toolbar 容器中,这样,更方便于管理和呈现 Menu 内容。

    所以,原本孤立的 Toolbar 控件,就有了一个 Child,使用如下:

    2. 基本使用

    1. app.build添加v7依赖 (正常用Toolbar时就导入了_

    compile 'com.android.support:appcompat-v7:25.3.1'
    

    2. xml中引用actionmenuview

     <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?actionBarSize"
        app:title="MainActivity"
        app:titleTextColor="#ffffff"
        android:background="@color/colorPrimary"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/AppTheme.ToolbarPopupTheme">
    
        <android.support.v7.widget.ActionMenuView
            android:id="@+id/amv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center">
    
        </android.support.v7.widget.ActionMenuView>
    
    </android.support.v7.widget.Toolbar>
    

    3. 将Toolbar的menu和menu点击事件,都转到actionmenuview中

     @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        ActionMenuView amv = (ActionMenuView) findViewById(R.id.amv);
        // 将menu加载到actionmenuview中
        getMenuInflater().inflate(R.menu.menu,amv.getMenu());
        // menuitem的点击事件
        amv.setOnMenuItemClickListener(new ActionMenuView.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                return onOptionsItemSelected(item);
            }
        });
    //        getMenuInflater().inflate(R.menu.menu,menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.menu_menu:
                Toast.makeText(this, "菜单", Toast.LENGTH_SHORT).show();
                break;
            case R.id.menu_home:
                Toast.makeText(this, "首页", Toast.LENGTH_SHORT).show();
                break;
            case R.id.menu_self:
                Toast.makeText(this, "个人中心", Toast.LENGTH_SHORT).show();
                break;
        }
        return true;
    }
    
    

    效果


    image image

    注意:给Toolbar设置的popupTheme,对于Actionmenuview不太起作用了。想想也是,现在的Actionmenuview取代了Toolbar原先管理的那个Menu,而且相对独立,不受Toolbar约束;这样Actionmenuview可以显示在Toolbar的任意位置,但同时Toolbar的popupTheme也对Actionmenuview不起作用了。所以我就直接给actionmenuview设置theme控制弹窗的主题,控制它的样式为白底黑字 (尝试过给ActionMenuView这是popupTheme,但是不起作用

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    ......
     </style>
     <!-- 自定义的popupTheme ,继承APPTheme,APPTheme继承的明亮系主题 -->
        <style name="AppTheme.ToolbarPopupTheme" >
            <!-- 不设置这个属性,三个点会是黑色 -->
            <item name="android:textColorSecondary">#ffffff</item>
            <!-- 设置Menu窗口不覆盖Toolbar视图 -->
            <item name="overlapAnchor">false</item>
        </style>
    
      <android.support.v7.widget.ActionMenuView
            ......
            app:theme="@style/AppTheme.ToolbarPopupTheme">
      </android.support.v7.widget.ActionMenuView>
    

    效果


    image

    不显示图标的问题,将上面重写的onPrepareOptionsMenu,修改一下代码如下: 移花接木

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // 用ActionMenuView的 Menu 替换原先的 Menu
        menu = mAmv.getMenu();
        if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
            try {
                Method m = menu.getClass().getDeclaredMethod(
                        "setOptionalIconsVisible", Boolean.TYPE);
                m.setAccessible(true);
                m.invoke(menu, true);
            } catch (NoSuchMethodException e) {
            } catch (Exception e) {
            }
        }
        return super.onPrepareOptionsMenu(menu);
    }
    

    效果


    image

    四、Fragment中使用Toolbar,添加optionMenu


    1. 在onCreateView()中添加代码,代替原有的ActionBar

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_toolbar, container, false);
        mToolbar = (Toolbar) view.findViewById(R.id.toolbar);
        // 代替Actionbar
        ((AppCompatActivity)getActivity()).setSupportActionBar(mToolbar);
        return view;
    }
    

    2. 在onCreate()中添加代码,告诉Activity需要创建optionMenu

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 告诉Activity有optionMenu
        setHasOptionsMenu(true);
    }
    
    

    3. 重写onCreateOptionMenu()方法,加载菜单

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        menu.clear();
        inflater.inflate(R.menu.menu,menu);
    }
    

    重写Fragment的onCreateOptionMenu()方法,覆盖Activity的onCreateOptionMenu()方法,否则Fragment中的onCreateOptionMenu()不会被调用

    4. 菜单点击事件

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            ......
            case R.id.menu_self:
                Toast.makeText(getActivity(), "个人中心", Toast.LENGTH_SHORT).show();
                break;
        }
        return true;
    }
    

    注意

    1. Activity中的onOptionsItemSelected不能返回true,否则Fragment中的onOptionsItemSelected点击事件无效
    2. ((AppCompatActivity)getActivity()).setSupportActionBar(mToolbar);的位置要在onCreateView中,刚开始测试时特别粗心,是在onCreate中写的,但是onCreate是在onCreateView之前调用,所以此时mToolbar为null,导致测试一直失败,toolbar虽然显示,但不正确,没有能代替Actionbar,Optionmenu也不显示
    image
    image

    GitHub示例:ViewDemo/ToolbarDemo


    个人总结,水平有限,如果有错误,希望大家能给留言指正!如果对您有所帮助,可以帮忙点个赞!如果转载,希望可以留言告知并在显著位置保留草帽团长的署名和标明文章出处!最后,非常感谢您的阅读!

    相关文章

      网友评论

        本文标题:Toolbar、ActionMenuView

        本文链接:https://www.haomeiwen.com/subject/jsvznxtx.html