解决Toolbar中的困惑,随心所欲定制Toolbar

前言:本文的重头戏在第4部分,主要讲解新手接触Toolbar时遇到的困惑和如何随心所欲地定制Toolbar,例如,

. 如何正确地使用Toolbar

. xml中设置属性无效

. 导航按钮的间距问题

. 自定义标题文字的大小和颜色

. 自定义ActoinView的文字大小和颜色

. 自定义溢出菜单的弹出窗口的背景、弹出位置

. 标题居中

 ...

1.Toolbar的组成

Toolbar是Android5.0(API 21)引入的,取代之前的ActionBar,它的本质是一个View,使用起来更加灵活,功能也更加强大。Toolbar的组成如下:

解决Toolbar中的困惑,随心所欲定制Toolbar_第1张图片

①为Toolbar,继承ViewGroup,是个普通的容器。

②为导航按钮,类型为ImageButton,可设置点击事件,用于返回上个页面或者滑出侧滑菜单。

    xml属性:app:navigationIcon 对应方法:setNavigationIcon(Drawable d) ,setNavigationIcon(int resId)

③为Logo展示图,类型为ImageView,不响应事件,仅仅作为展示。

    xml属性:app:logo 对应方法:setLogo(Drawable d) ,setLogo(int resId)

④为主标题,类型为TextView

    xml属性:app:title 对应方法:setTitle(CharSequence title),setTitle(int resId)

⑤为副标题,类型为TextView

    xml属性:app:subtitle 对应方法:setSubtitle(CharSequence title),setSubtitle(int resId)

⑥为普通子View,标题和ActionMenuView之间是留给我们添加子View的区域

⑦为ActionMenuView,负责管理选项菜单

2.在布局文件中使用Toolbar



    
        
    

Toolbar的高度我们使用当前主题下ActionBar的高度,Toolbar默认没有背景,通常使用@color/colorPrimary

3.在代码中处理Toolbar

        //像获取普通控件那样获取Toolbar
        mToolbar = (Toolbar) findViewById(R.id.toolbar);

        //以下四个方法分别用来设置导航按钮、Logo、主标题和副标题
        //如果xml文件中没有设置这些属性或者想覆盖xml文件中设置的值可调用这些方法
        mToolbar.setNavigationIcon(R.drawable.nav_icon);
        mToolbar.setLogo(R.drawable.logo_icon);
        mToolbar.setTitle("主标题");
        mToolbar.setSubtitle("副标题");
        //设置导航按钮的点击事件
        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "点击了导航按钮!", Toast.LENGTH_SHORT).show();
            }
        });
        //生成选项菜单
        mToolbar.inflateMenu(R.menu.action_menu_main);
        //设置选项菜单的菜单项的点击事件
        mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                Toast.makeText(MainActivity.this, "点击了菜单项" + item.getTitle(), Toast.LENGTH_SHORT).show();
                return true;
            }
        });

        //获取选项菜单,可增加,减少菜单项
        Menu menu = mToolbar.getMenu();
        menu.add("测试菜单项");
        menu.removeItem(R.id.item_04);

        //设置溢出菜单的icon,显示、隐藏溢出菜单弹出的窗口
        mToolbar.setOverflowIcon(ContextCompat.getDrawable(this,android.R.drawable.ic_menu_more));
        mToolbar.showOverflowMenu();
        mToolbar.dismissPopupMenus();

选项菜单如下:



    
    
    
    


看一下运行效果:

解决Toolbar中的困惑,随心所欲定制Toolbar_第2张图片


4.解决Toolbar中的困惑以及定制Toolbar

①如何正确地使用Toolbar

Toolbar是Android5.0(API 21)引入的,为了兼容低版本,我们不要使用android.widget.Toolbar,而是android.support.v7.widget.Toolbar。v7库最低兼容API  7,咱们一般的应用兼容到API 15足够,即便是开发第三方SDK,一般也只兼容到API 10,所以我们完全不用担心低版本的兼容问题。

Toolbar也可以如此使用,转化成ActionBar

        setSupportActionBar(mToolbar);
这样一来,选项菜单就得按照之前ActionBar的方式设置,在Activity中重写下列方法,

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.action_menu_main,menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Toast.makeText(MainActivity.this, "点击了菜单项" + item.getTitle(), Toast.LENGTH_SHORT).show();
        return true;
    }
Toolbar的出现就是为了取代ActionBar,所以我们强烈建议不要按上述方式使用Toolbar,将其与ActionBar纠缠在一起。Toolbar无论在灵活上、功能上都把AcionBar甩好几条街。交织在一起,使用不当的话,反而引入稀奇古怪的Bug,真是得不偿失。

.xml中设置属性无效

    
上面的设置中,id,layout_width,layout_height,background有效,而后四个属性无效。解决办法是将后四个属性的命名空间改成app。

    
这是为什么?

前四个属性是非兼容库中SDK本身就有的属性,他们的命名空间是android,而后四个属性是Toolbar的专有属性,我们使用的是支持库中的Toolbar,所以要用自定义命名空间,所以需要使用app。

③导航按钮的左右间距问题

Toolbar的布局规则:默认状况下,上下左右的内边距皆为0,导航按钮和选项菜单分别紧靠Toolbar的左右两端,其他内容插入他们二者之间。

我们去主题中看一下导航按钮的默认样式,

    
显示导航图标的ImageButton本身是紧靠Toolbar左边缘,无外边距的,不过它的最小宽度是56dp,缩放类型为只居中不缩放,所以在视觉效果上,跟Toolbar边缘有一定距离。有的时候这种距离并不合适,我们可以这样改变它。

第一步,自定义一个样式

    

第二步,在主题中指定toolbarNavigationButtonStyle使用上面定义的样式

    

我们把ImageButton的最小宽度设为0。如果美工切给你的图本身周边有空白的透明区域,你可以把左右内边距设置为0或其他合适的值进行调整。如果没有,设置为16dp即可。

不要通过给ImageButton设置外边距的方式形成间距,虽然视觉效果一样,但是导航按钮是响应用户点击的,内边距依然是View的一部分,依然在响应触碰的范围内,这样用户的体验较好,避免图标过小时,用户“不易”触发点击事件。

其他内容插入导航按钮和选项菜单之间时,受四个xml属性的影响:contentInsetStart、contentInsetStartWithNavigation、contentInsetEnd、contentInsetEndWithActions;

    

contentInsetStart默认值为16dp,contentInsetStartWithNavigation默认值为72dp,其他两个属性的默认值为0。

导航按钮存在,内容插入的左间距取contentInsetStart和contentInsetStartWithNavigation的最大值,否则取contentInsetStart的值。

也就是说contentInsetStartWithNavigation只在导航按钮存在时有效,contentInsetStart无论是否存在都有效。

同理,选项菜单存在,内容插入的右间距取contentInsetEnd和contentInsetEndWithActions的最大值,否则取contentInsetEnd的值。

也就是说,contentInsetEndWithActions只在选项菜单存在时有效,contentInsetEnd无论是否存在都有效。

所以,如果改变导航按钮右间距,只需如此设置,

    
因为前面我们已经给导航按钮设置了16dp的右内边距,所以这里设为0dp就可以了。

④.标题文字的大小和颜色

以主标题为例,如果仅需改变字体颜色,可以通过app:titleTextColor="#ffffff"设置。如果需要改变大小,自定义一个样式,

    

然后设置app:titleTextAppearance="@style/toolbar_title_style"。倘若app:titleTextColor与app:titleTextAppearance中均指定了字体颜色,前者会覆盖后者。另外,主题中title上下左右均有4pd的外边距,可通过app:titleMargin,app:titleMarginStart,app:titleMarginEnd,app:titleMarginTop,app:titleMarginBottom来改变。主题中的默认值如下,

    

⑤.定制Toolbar选项菜单项

选项菜单项在Toolbar上显示时,有可能是图标,也有可能是文字,我们可以自定义他们的字体大小,颜色以及他们之间的间距。先看看它的默认样式,

    
    

values-v21

    

自定义一个样式,

    
注意,在API 21以下,资源文件定义了paddingLeft和paddingRight,API 21及以上定义了paddingStart和paddingEnd,这里为了适配同时指定了四个属性。字体颜色在这里指定是无效的,需在主题中指定android:actionMenuTextColor的值。

在主题中使用该样式,并指定android:actionMenuTextColor的值,

    
⑥.溢出按钮的样式

溢出按钮的样式,通过在主题中设置android:actionOverflowButtonStyle来指定,不过一般我们不会自定义它的样式,另外,通过代码可以替换溢出按钮的图标,setOverflowIcon(Drawable d)

    

    

⑦.自定义弹出的溢出菜单的背景、弹出位置

看看默认样式,

    

自定义样式,

    
在主题中指定使用该样式,

    

字体的颜色和大小通过Toolbar的xml属性app:popupTheme="@style/toolbar_pop_theme"指定

    


⑧标题居中问题

很少有产品经理设计标题居中的了,但如果有,可以如此解决,

    
        
        
效果如下,

解决Toolbar中的困惑,随心所欲定制Toolbar_第3张图片

5.最后送上所有源码

package coder.zzq.toolbardemo;

import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

import programmer.zzq.toolbardemo.R;

public class MainActivity extends AppCompatActivity {
    private Toolbar mToolbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //像获取普通控件那样获取Toolbar
        mToolbar = (Toolbar) findViewById(R.id.toolbar);

        //以下四个方法分别用来设置导航按钮、Logo、主标题和副标题
        //如果xml文件中没有设置这些属性或者想覆盖xml文件中设置的值可调用这些方法
        mToolbar.setNavigationIcon(R.drawable.nav_icon);
        mToolbar.setLogo(R.drawable.logo_icon);
        mToolbar.setTitle("主标题");
        mToolbar.setSubtitle("副标题");

        //设置导航按钮的点击事件
        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "点击了导航按钮!", Toast.LENGTH_SHORT).show();
            }
        });

        //生成选项菜单
        mToolbar.inflateMenu(R.menu.action_menu_main);
        //设置选项菜单的菜单项的点击事件
        mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                Toast.makeText(MainActivity.this, "点击了菜单项" + item.getTitle(), Toast.LENGTH_SHORT).show();
                return true;
            }
        });

        //获取选项菜单,可增加,减少菜单项
        Menu menu = mToolbar.getMenu();
        menu.add("测试菜单项");
        menu.removeItem(R.id.item_04);

        //设置溢出菜单的icon,显示、隐藏溢出菜单弹出的窗口
        mToolbar.setOverflowIcon(ContextCompat.getDrawable(this,android.R.drawable.ic_menu_more));
        mToolbar.showOverflowMenu();
        mToolbar.dismissPopupMenus();
        
    }


}
布局文件




    


菜单资源



    
    
    
    
样式资源



    
    

    

    

    

    

    

    


    


最终的运行效果:

解决Toolbar中的困惑,随心所欲定制Toolbar_第4张图片








后期追加:

有的时候,我们想要显示溢出菜单项的图标,就像微信这样:

解决Toolbar中的困惑,随心所欲定制Toolbar_第5张图片

通过一行代码即可实现:

        ((MenuBuilder) mToolbar.getMenu()).setOptionalIconsVisible(true);

效果图:

解决Toolbar中的困惑,随心所欲定制Toolbar_第6张图片

布局文件:




    
菜单资源:



    
    
    
    
主题设置:



    
    


    


    





你可能感兴趣的:(Widgets)