Android自定义Toolbar以及设置圆形导航图标

我们希望可以自定义Toolbar,实现一些特定的功能,android.support.v7.widget.Toolbar正好完成这些工作

首先看一下我们预期的效果图:


先看一下Toolbar的布局

<android.support.design.widget.AppBarLayout
    android:id="@+id/app_bar_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:contentInsetStart="0dp"
        app:popupTheme="@style/toolbar_action_menu_overflow"
        android:background="@drawable/title_bar">

        <TextView
            android:id="@+id/toolbar_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:singleLine="true"
            android:textColor="@android:color/white"
            android:textSize="20sp" />

    </android.support.v7.widget.Toolbar>

</android.support.design.widget.AppBarLayout>

这里背景的渐变色可以通过定义如下xml来实现,同时将Toolbar的background设置为该xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient
        android:angle="135"
        android:endColor="#508eff"
        android:centerColor="#35b1fd"
        android:startColor="#65ccff"
        android:type="linear" />
</shape>

为了使标题可以居中显示,在Toolbar中添加了一个TextView用来显示标题,并且需要在Activity中将原标题隐藏

toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayUseLogoEnabled(false);

在DrawerLayout中,我们新建ActionBarDrawerToggle并且传入toolbar,我们希望更改Toolbar的导航按钮图标,注意这个操作必须在setSupportActionBar和addDrawerListener操作之后

Resources resources = MainActivity.this.getResources();
Drawable drawable = resources.getDrawable(R.drawable.image);
int size = 44;
CircleDrawable circleDrawable = new CircleDrawable(drawable, MainActivity.this, size);
toolbar.setNavigationIcon(circleDrawable);

CircleDrawable是我自己定义为了绘制原型图标的Drawable

package com.sdu.runningsdu.Utils;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.TypedValue;

/**
 * Created by FTDsm on 2018/6/7.
 */

public class CircleDrawable extends Drawable {

    private Bitmap bitmap;

    private BitmapShader bitmapShader;

    private Paint paint;

    // 圆心
    private float cx, cy;

    // 半径
    private float radius;

    public CircleDrawable(Drawable drawable, Context context, int size) {
        size = dip2px(context, size);
        drawable = zoomDrawable(drawable, dip2px(context, size), dip2px(context, size));
        this.bitmap = drawableToBitmap(drawable);
        bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(bitmapShader);

        cx = size / 2;
        cy = size / 2;
        radius = size / 2;
    }

    @Override
    public void draw(@NonNull Canvas canvas) {
        canvas.drawCircle(cx, cy, radius, paint);
    }

    /**
     * 缩放Drawable
     * */
    private Drawable zoomDrawable(Drawable drawable, int w, int h) {
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        Bitmap oldbmp = drawableToBitmap(drawable);
        Matrix matrix = new Matrix();
        float scaleWidth = ((float) w / width);
        float scaleHeight = ((float) h / height);
        matrix.postScale(scaleWidth, scaleHeight);
        Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height,
                matrix, true);
        return new BitmapDrawable(null, newbmp);
    }

    /**
     * Drawable转Bitmap
     * */
    private Bitmap drawableToBitmap(Drawable drawable) {
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
                : Bitmap.Config.RGB_565;
        Bitmap bitmap = Bitmap.createBitmap(width, height, config);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, width, height);
        drawable.draw(canvas);
        return bitmap;
    }

    /**
     * dp to px
     * */
    private int dip2px(Context context, float dipValue) {
        Resources resources = context.getResources();
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, resources.getDisplayMetrics());
    }

    public static int dip2px1(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    private int dip2px2(Context context,float dpValue){
        float scale=context.getResources().getDisplayMetrics().density;
        return (int)(dpValue*scale+0.5f);
    }

    @Override
    public void setAlpha(int alpha) {
        paint.setAlpha(alpha);
    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {
        paint.setColorFilter(colorFilter);
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }
}

工具栏右侧的菜单可以通过menu设置,以下代码可以完成menu的初始化和无法同时显示图标和文字的问题

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

/**
 * 解决Toolbar中Menu无法同时显示图标和文字的问题
 * */
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
    if (menu != null) {
        if (menu.getClass().getSimpleName().equalsIgnoreCase("MenuBuilder")) {
            try {
                Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
                method.setAccessible(true);
                method.invoke(menu, true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    return super.onMenuOpened(featureId, menu);
}

溢出菜单可以通过定义style来配置,并且要将其添加到Activity Theme style中

<style name="toolbar_action_menu_overflow" parent="Widget.AppCompat.PopupMenu.Overflow">
    <!--是否覆盖锚点-->
    <item name="overlapAnchor">false</item>
    <!--弹出层水平方向上的偏移,负值为距离右边的空隙-->
    <item name="android:dropDownHorizontalOffset">-10dp</item>
    <!-- 弹出层垂直方向上的偏移,负则会盖住Toolbar -->
    <item name="android:dropDownVerticalOffset">5dp</item>
    <item name="android:divider">@color/colorPrimaryDark</item>
    <item name="android:dividerHeight">1dp</item>
    <item name="android:textColor">@android:color/white</item>
    <item name="android:popupBackground">#48bbfd</item>
</style>

弹出菜单可以通过setOnMenuItemClickListener设置点击事件

toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
    @Override
    public boolean onMenuItemClick(MenuItem item) {
        int id = item.getItemId();
        Intent intent;
        switch (id) {
            case R.id.item_create_group:
                break;
            case R.id.item_add_friend:
                break;
            case R.id.item_scan:
                break;
            case R.id.item_help_and_feedback:
                break;
        }
        return true;
    }
});

最后如果Toolbar遮挡了content_main.xml,在其被遮挡的布局设置app:layout_behavior属性即可

app:layout_behavior="@string/appbar_scrolling_view_behavior"

猜你喜欢

转载自blog.csdn.net/baidu_34045013/article/details/80700226
今日推荐