我們希望可以自定義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"