学习笔记:Toolbar、ActionMenuView的使用

一、ActionBar


操作栏,用于页面导航和其他项交互。从Android 3.0(API级别11)开始,当Activity使用系统的Holo主题(或其子主题)时,操作栏将显示在活动窗口的顶部,这是默认设置。

1、ActionBar隐藏方式

代码中隐藏

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 一定要在setContentView()之前调用
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        
        // 继承Activity的话,使用下面这个
        // requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
    }

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>

2、常用方法

  • setDisplayHomeAsUpEnabled(boolean showHomeAsUp)
    是否显示返回按钮,true:显示默认返回按钮

  • setHomeAsUpIndicator(int resId)
    自定义返回按钮

  • setDisplayShowTitleEnabled(boolean showTitle)
    设置是否显示标题

二、Toolbar


1. 简介

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

Toolbar属性

 <declare-styleable name="Toolbar">
    <!--标题文字外观-->
    <attr name="titleTextAppearance" format="reference" />
    <!--副标题文字外观-->
    <attr name="subtitleTextAppearance" format="reference" />
    <!--标题-->
    <attr name="title" />
    <!--副标题-->
    <attr name="subtitle" />
    <!-- 标题字体颜色 -->
    <attr name="titleTextColor" format="color" />
    <!-- 副标题字体颜色 -->
    <attr name="subtitleTextColor" format="color" />
    <!--重心-->
    <attr name="gravity" />
    <!--标题的外边距 , titleMargin默认4dp-->
    <attr name="titleMargin" format="dimension" />
    <attr name="titleMarginStart" format="dimension" />
    <attr name="titleMarginEnd" format="dimension" />
    <attr name="titleMarginTop" format="dimension" />
    <attr name="titleMarginBottom" format="dimension" />
    <!--内容插入位置,(start默认16dp 比如我们有个标题,现在距离左边是16dp的)-->
    <attr name="contentInsetStart" /> <!-- 去除toolbar左侧边距,就是将该属性设置为0dp-->
    <attr name="contentInsetEnd" />
    <attr name="contentInsetLeft" />
    <attr name="contentInsetRight" />
    <!--有导航按钮时内容插入位置,默认72dp ,即导航按钮宽高为56dp + titleMargin(16dp)-->
    <attr name="contentInsetStartWithNavigation" />
    <!--有操作栏时内容End处插入位置-->
    <attr name="contentInsetEndWithActions" />
    <!--导航按钮button最大高度,默认56dp(?actionBarSize)-->
    <attr name="maxButtonHeight" format="dimension" />
    <!--导航按钮button样式-->
    <attr name="navigationButtonStyle" format="reference" />
    <!--导航按钮在Toolbar中的位置-->
    <attr name="buttonGravity">
        <flag name="top" value="0x30" />
        <flag name="bottom" value="0x50" />
    </attr>
    <!-- 折叠时的按钮icon -->
    <attr name="collapseIcon" format="reference" />
    <!-- 折叠按钮的内容描述 -->
    <attr name="collapseContentDescription" format="string" />
    <!-- toolbar上弹出窗口的样式 -->
    <attr name="popupTheme" format="reference" />
    <!-- 导航按钮 -->
    <attr name="navigationIcon" format="reference" />
    <!-- 导航按钮描述 -->
    <attr name="navigationContentDescription" format="string" />
    <!-- 在导航按钮后显示的一个图片 -->
    <attr name="logo" />
    <!-- logo描述-->
    <attr name="logoDescription" format="string" />
   
</declare-styleable>

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);


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

3. 要点

1. NavigationIcon

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

1.代码设置显示

 getSupportActionBar().setDisplayHomeAsUpEnabled(true);


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);

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>

效果

如果在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);

效果

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;
    }

效果

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属性,弹出菜单会变为黑底白字

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



可以看出,不管是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"">

效果

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);
}

效果

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;
}

效果

注意:给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>

效果

不显示图标的问题,将上面重写的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);
}

效果

四、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);
    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也不显示


GitHub示例:ViewDemo/ToolbarDemo


个人总结,水平有限,如果有错误,希望大家能给留言指正!如果对您有所帮助,可以帮忙点个赞!如果转载,希望可以标明文章出处!最后,非常感谢您的阅读!

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值