Android MaterialAndroid开发Android开发经验谈

Material Design - Toolbar

2017-10-20  本文已影响69人  Arnold_J

关键字:Toolbar、材料设计
项目地址:AboutMaterialDesign


一、从官网了解

链接:Toolbar
安卓 app 大多有标题栏这个 UI 功能,但是系统自带的 actionbar 已经没法满足日益进步的 UI 设计,为此在材料设计的支持包中,添加了 Toolbar 这个控件。Toolbar 可以作为一个普通的控件添加在任意视图层级中,同时也可以利用 setSupportedActionBar() 将其设置为 Activity 的 action bar。

Toolbar 提供了更加丰富的配置功能,在布局上从左到右主要有以下几点:

主要内容就是这些,下面都是一些方法和属性介绍,内容太多,就不再绘制表格了。

二、简单使用

首先,记得设置 AppTheme 为 NoActionBar,具体操作为更改 res/style/AppTheme 里的内容

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

然后记得在 onCreate 方法里,调用 setSupportActionBar(mToolbar);
讲完基本,现在来看看最简单的使用。

2.1 Navigation Button && Logo Image && Title and Subtitle
<android.support.v7.widget.Toolbar
    android:background="@color/colorPrimary"
    android:id="@+id/activity_toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    app:navigationIcon="@drawable/ic_list"
    app:logo="@drawable/ic_down"
    app:title="Title"
    app:titleTextColor="@android:color/white"
    app:subtitle="subTitle"
    app:subtitleTextColor="@android:color/white"
></android.support.v7.widget.Toolbar>

得到下面的效果:

Toolbar效果图
2.2 Custom View
View addView = LayoutInflater.from(mToolbar.getContext()).inflate(R.layout.snack_custom_img, null);
Toolbar.LayoutParams p = new Toolbar.LayoutParams( Toolbar.LayoutParams.WRAP_CONTENT,Toolbar.LayoutParams.WRAP_CONTENT, Gravity.RIGHT);
addView.setLayoutParams(p);
mToolbar.addView(addView);

通过上面的方法就可以向 Toolbar 中添加自定义的视图。默认 Gravity 为 CENTER_VERTICAL | START,这块代码主要可以看 Toolbar 的 onlayout 方法。

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    
    //...一些变量声明

    // Align views within the minimum toolbar height, if set.
    final int minHeight = ViewCompat.getMinimumHeight(this);
    final int alignmentHeight = minHeight >= 0 ? Math.min(minHeight, b - t) : 0;

    if (shouldLayout(mNavButtonView)) {
        ...
    }

    if (shouldLayout(mCollapseButtonView)) {
        ...
    }

    if (shouldLayout(mMenuView)) {
        ...
    }

    if (shouldLayout(mExpandedActionView)) {
        ...
    }

    if (shouldLayout(mLogoView)) {
        ...
    }

    if (layoutTitle) {
        ...
    }
    if (layoutSubtitle) {
        ...
    }

    if (layoutTitle || layoutSubtitle) {
        
        switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
            case Gravity.TOP:
                ...
                break;
            default:
            case Gravity.CENTER_VERTICAL:
                ...
                break;
            case Gravity.BOTTOM:
                ...
                break;
        }
        ...
    }

    // Get all remaining children sorted for layout. This is all prepared
    // such that absolute layout direction can be used below.

    addCustomViewsWithGravity(mTempViews, Gravity.LEFT);
    final int leftViewsCount = mTempViews.size();
    for (int i = 0; i < leftViewsCount; i++) {
        left = layoutChildLeft(mTempViews.get(i), left, collapsingMargins,
                alignmentHeight);
    }

    addCustomViewsWithGravity(mTempViews, Gravity.RIGHT);
    final int rightViewsCount = mTempViews.size();
    for (int i = 0; i < rightViewsCount; i++) {
        right = layoutChildRight(mTempViews.get(i), right, collapsingMargins,
                alignmentHeight);
    }

    // Centered views try to center with respect to the whole bar, but views pinned
    // to the left or right can push the mass of centered views to one side or the other.
    addCustomViewsWithGravity(mTempViews, Gravity.CENTER_HORIZONTAL);
    ...

    mTempViews.clear();
}

可以看到,Toolbar 依次放置完内部的控件后,开始根据 Gravity 放置自定义 View。其中 addCustomViewsWithGravity 方法主要功能是把相同 Gravity 的 View 依次取出放入 mTempViews,之后再根据规则进行放置。这里,代码用最简单的 ImageView 布局靠右演示。

customView.png

以上就是 customview 的全部内容,说到底这个东西方法简单,重在想象力和其他控件的综合使用。


2.3 ActionMenu

在 res/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">
    <!--说明
        1.orderInCategory 表示显示的次序
        2.showAsAction: never ifroom always
            never   总是在 pop 菜单中显示
            ifroom  如果有空间则在 actionbar 上显示,否则在 pop 菜单中显示
            always  总是在 actionbar 上显示
        -->
    <item
        android:title="收藏"
        android:id="@+id/menu_action_item1"
        android:icon="@drawable/ic_like"
        android:orderInCategory="1"
        app:showAsAction="never" />

    <item
        android:title="分享"
        android:id="@+id/menu_action_item2"
        android:icon="@drawable/ic_share"
        android:orderInCategory="2"
        app:showAsAction="always" />

    <item
        android:title="设置"
        android:id="@+id/menu_action_item3"
        android:orderInCategory="3"
        android:icon="@drawable/ic_set"
        app:showAsAction="never" />

</menu>

接下来在 ToolbarActivity 中重写下面的几个方法:


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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_action_item1:
                Log.i(TAG, "onMenuItemClick: like");
                makeText(ToolbarActivity.this, "like", Toast.LENGTH_SHORT).show();
                break;
            case R.id.menu_action_item2:
                Log.i(TAG, "onMenuItemClick: share");
                makeText(ToolbarActivity.this, "share", Toast.LENGTH_SHORT).show();
                break;
            case R.id.menu_action_item3:
                Log.i(TAG, "onMenuItemClick: setup");
                makeText(ToolbarActivity.this, "setup", Toast.LENGTH_SHORT).show();
                break;
        }
        return super.onOptionsItemSelected(item);
    }

效果图:

效果图.gif

这里我们可以看到这样几个问题:

下面来看如何修改这几个问题:


    <!-- Toolbar ActionMenu 样式 -->
    <style name="CustomPopupTheme" parent="ThemeOverlay.AppCompat.Light">
        <item name="android:textColor">@android:color/white</item>
        <item name="android:textSize">14sp</item>
        <item name="android:colorBackground">@color/colorPrimary</item>
        <!--overlapAnchor 是让 ActionMenu 不要盖住ToolBar-->
        <item name="overlapAnchor">false</item>
    </style>

GIF.gif
<!-- ActionMenu 图标颜色-->
<item name="android:actionMenuTextColor">#ffffff</item>
<item name="android:textColorSecondary">@android:color/white</item>
<item name="android:colorControlNormal">@android:color/white</item>
右上角图标变白.png
mToolbar.setOverflowIcon(getResources().getDrawable(R.drawable.ic_more));//更改右上角图标
右上角图标变白.png

三、遇到的小问题

1.右上角 actionMenu 不显示

这个是因为有的手机自带了菜单键,系统中默认不显示那三个点的图标,因系统而异。最方便的解决办法是把手机的设备信息改为没有菜单键。

try {
    ViewConfiguration config = ViewConfiguration.get(this);
    Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
    if (menuKeyField != null) {
        menuKeyField.setAccessible(true);
        menuKeyField.setBoolean(config, false);
    }
} catch (Exception e) {
    e.printStackTrace();
}
参考链接:https://www.pocketdigi.com/20141024/1388.html

2.mToolbar.setNavigationOnClickListener 不起作用
把相关方法放在 setSupportedActionBar 之后


本来觉得一篇可以把这个结束,但是仔细实现起来发现 ActionMenu 的问题还是挺多的,因此会另起一篇,写写利用 ActionMenu 实现具体效果的时候遇到的问题。

谢谢观赏
上一篇下一篇

猜你喜欢

热点阅读