最近在仿手Q的UI,這裏面經常要用到的就是圓形頭像,看到 在android中畫圓形圖片的幾種辦法 這篇文章,瞭解了製作這種頭像的原理.不過裏面提供的方法還有一個不足的地方就是不能根據實際需求改變圖片的大小,也就是說提供的原圖是大尺寸的,轉換之後的圖片也是大尺寸的,這顯然不符合我們實際項目中的需求.於是我對裏面介紹的第一種方法做了一番改進,使其能直接在XML中指定圖片的大小.
大體步驟
- 將原圖居中裁剪成正方形
- 根據指定的寬度對正方形進行縮放
- 裁剪成圓形
效果
代碼實現
package com.demos.tencent_qq_ui.CustomerView;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* Created by mummyding on 15-8-7.
*/
public class AvatarImageView extends ImageView {
private Paint paint = new Paint();
public AvatarImageView(Context context) {
super(context);
}
public AvatarImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AvatarImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
//將頭像按比例縮放
private Bitmap scaleBitmap(Bitmap bitmap){
int width = getWidth();
//一定要強轉成float 不然有可能因爲精度不夠 出現 scale爲0 的錯誤
float scale = (float)width/(float)bitmap.getWidth();
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
//將原始圖像裁剪成正方形
private Bitmap dealRawBitmap(Bitmap bitmap){
int width = bitmap.getWidth();
int height = bitmap.getHeight();
//獲取寬度
int minWidth = width > height ? height:width ;
//計算正方形的範圍
int leftTopX = (width - minWidth)/2;
int leftTopY = (height - minWidth)/2;
//裁剪成正方形
Bitmap newBitmap = Bitmap.createBitmap(bitmap,leftTopX,leftTopY,minWidth,minWidth,null,false);
return scaleBitmap(newBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (null != drawable) {
Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap();
//處理Bitmap 轉成正方形
Bitmap newBitmap = dealRawBitmap(rawBitmap);
//將newBitmap 轉換成圓形
Bitmap circleBitmap = toRoundCorner(newBitmap, 14);
final Rect rect = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight());
paint.reset();
//繪製到畫布上
canvas.drawBitmap(circleBitmap, rect, rect, paint);
} else {
super.onDraw(canvas);
}
}
private Bitmap toRoundCorner(Bitmap bitmap, int pixels) {
//指定爲 ARGB_4444 可以減小圖片大小
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Rect rect = new Rect(0, 0,bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
int x = bitmap.getWidth();
canvas.drawCircle(x / 2, x / 2, x / 2, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
}
然後就可以直接像其他View一樣直接在XML中使用了.
例如
<com.demos.tencent_qq_ui.CustomerView.AvatarImageView
android:layout_width="96dip" <!--可自行指定大小-->
android:layout_height="96dip"
android:layout_centerHorizontal="true"
android:src="@drawable/avatar" <!--這裏放圖片-->
/>
這樣,在界面上顯示的圖像就是圓形的了.
不過我這裏還有一個不足的地方是沒有檢查原圖片的大小,如果你放一張高清的圖片,那就很可能crash 掉.對於這點,我目前的解決方法就是 Google 官方教程裏的 Loading
Large Bitmaps Efficiently 但它的原理就是先不不把圖片加載進來,而是先根據原圖的大小計算縮放值,然後在根據縮放值讀取圖片(算是在讀取的時候進行壓縮吧....).但是這個方法需要提供視圖ID,也就是說要給AvatarImageView 指定一個ID,然後一個AvatarImageView 要對應一個視圖(我是這麼理解的) 這樣的話AvatarImageView就無法重用了.當項目中多處要用到這個的話就會很麻煩.
爲此我在stackoverflow提了一個問,但是目前還沒有人回答T_T How
to make bitmap(set in src) compress?