RoundedBitmapDrawable 是 Android 版本 22.1.0 的時候加入的,它的主要做用是建立圓角的 Drawable。android
A Drawable that wraps a bitmap and can be drawn with rounded corners.canvas
Google 添加此類的緣由多是彌補 Android API 中沒有直接支持建立圓角 Drawable 的空缺吧。bash
RoundedBitmapDrawable 不只能夠建立圓角的 Drawable,還能夠建立圓角矩形的 Drawable,接下來,咱們就針對這兩種狀況分別討論。app
建立和應用 RoundedBitmapDrawable 一共分三步:ide
RoundedBitmapDrawable circleDrawable = RoundedBitmapDrawableFactory.create(@NonNull Resources res, @Nullable Bitmap bitmap);
複製代碼
RoundedBitmapDrawable.setCircular(boolean circular);
複製代碼
ImageView.setImageDrawable(@Nullable Drawable drawable);
複製代碼
//1. 資源文件
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".roundedbitmapdrawabletutorial.RoundedBitmapDrawableTutorialActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/rounded_bitmap_drawable_circle_fit_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_small"
android:background="@color/white"
android:scaleType="fitCenter"
android:src="@drawable/tiger" />
</LinearLayout>
</ScrollView>
複製代碼
//2. Activity
public class RoundedBitmapDrawableTutorialActivity extends AppCompatActivity {
private int mScreenWidth, mScreenHeight, mViewWidth, mViewHeight;
private ImageView mCircleFitCenterView;
private LinearLayout.LayoutParams mCircleLayoutParams;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rounded_bitmap_drawable_tutorial);
getScreenProperty();
initView();
initData();
}
private void getScreenProperty(){
mScreenWidth = DisplayMetricsUtil.getScreenWidth(this);
mScreenHeight = DisplayMetricsUtil.getScreenHeight(this);
mViewWidth = mScreenWidth * 2/3;
mViewHeight = mScreenHeight * 2/3;
}
private void initView(){
mCircleFitCenterView = findViewById(R.id.rounded_bitmap_drawable_circle_fit_center);
mCircleLayoutParams = new LinearLayout.LayoutParams(mViewWidth, mViewWidth);
mCircleLayoutParams.topMargin = (int)getResources().getDimension(R.dimen.padding_small);
mCircleFitCenterView.setLayoutParams(mCircleLayoutParams);
}
private void initData(){
//第一步
RoundedBitmapDrawable circleDrawable = RoundedBitmapDrawableFactory.create(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.tiger));
//第二步
circleDrawable.setCircular(true);
//第三步
mCircleFitCenterView.setImageDrawable(circleDrawable);
}
}
複製代碼
最終效果以下:工具
建立和應用 RoundedBitmapDrawable 一共分三步:post
RoundedBitmapDrawable circleDrawable = RoundedBitmapDrawableFactory.create(@NonNull Resources res, @Nullable Bitmap bitmap);
複製代碼
RoundedBitmapDrawable.setCornerRadius(float cornerRadius);
複製代碼
ImageView.setImageDrawable(@Nullable Drawable drawable);
複製代碼
//1. 資源文件
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".roundedbitmapdrawabletutorial.RoundedBitmapDrawableTutorialActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/rounded_bitmap_drawable_round_rectangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_small"
android:background="@color/white"
android:scaleType="fitCenter"
android:src="@drawable/tiger" />
</LinearLayout>
</ScrollView>
複製代碼
//2. Activity
public class RoundedBitmapDrawableTutorialActivity extends AppCompatActivity {
private int mScreenWidth, mScreenHeight, mViewWidth, mViewHeight;
private ImageView mRoundRectangleView;
private LinearLayout.LayoutParams mRoundRectangleLayoutParams;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rounded_bitmap_drawable_tutorial);
getScreenProperty();
initView();
initData();
}
private void getScreenProperty(){
mScreenWidth = DisplayMetricsUtil.getScreenWidth(this);
mScreenHeight = DisplayMetricsUtil.getScreenHeight(this);
mViewWidth = mScreenWidth * 2/3;
mViewHeight = mScreenHeight * 2/3;
}
private void initView(){
mRoundRectangleView = findViewById(R.id.rounded_bitmap_drawable_round_rectangle);
mRoundRectangleLayoutParams = new LinearLayout.LayoutParams(mViewWidth, mViewHeight);
mRoundRectangleLayoutParams.topMargin = (int)getResources().getDimension(R.dimen.padding_small);
mRoundRectangleView.setLayoutParams(mRoundRectangleLayoutParams);
}
private void initData(){
//第一步
RoundedBitmapDrawable roundRectangleDrawable = RoundedBitmapDrawableFactory.create(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.tiger));
//第二步
roundRectangleDrawable.setCornerRadius((mViewWidth < mViewHeight ? mViewWidth : mViewHeight)/32);
//第三步
mRoundRectangleView.setImageDrawable(roundRectangleDrawable);
}
}
複製代碼
最終效果以下:測試
只須要對 RoundedBitmapDrawable 的圓角的半徑稍做修改,就能夠的獲得以下效果:ui
修改方法以下:this
//第一步
RoundedBitmapDrawable roundRectangleDrawable = RoundedBitmapDrawableFactory.create(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.tiger));
//第二步
roundRectangleDrawable.setCornerRadius((mViewWidth < mViewHeight ? mViewWidth : mViewHeight)/2));
//第三步
mRoundRectangleView.setImageDrawable(roundRectangleDrawable);
複製代碼
是否是很好用?
知道了怎麼用 RoundedBitmapDrawable 以後,讓咱們一塊看下,RoundedBitmapDrawable 究竟是如何「變圓」的。
create(@NonNull Resources res, @Nullable Bitmap bitmap)
方法:public static RoundedBitmapDrawable create(@NonNull Resources res, @Nullable Bitmap bitmap) {
return (RoundedBitmapDrawable)(VERSION.SDK_INT >= 21 ? new RoundedBitmapDrawable21(res, bitmap) : new RoundedBitmapDrawableFactory.DefaultRoundedBitmapDrawable(res, bitmap));
}
複製代碼
在這裏咱們只研究 VERSION.SDK_INT 小於 21 的狀況,另一種狀況,你們本身去分析吧。
DefaultRoundedBitmapDrawable
方法:private static class DefaultRoundedBitmapDrawable extends RoundedBitmapDrawable {
DefaultRoundedBitmapDrawable(Resources res, Bitmap bitmap) {
super(res, bitmap);
}
public void setMipMap(boolean mipMap) {
if (this.mBitmap != null) {
BitmapCompat.setHasMipMap(this.mBitmap, mipMap);
this.invalidateSelf();
}
}
public boolean hasMipMap() {
return this.mBitmap != null && BitmapCompat.hasMipMap(this.mBitmap);
}
void gravityCompatApply(int gravity, int bitmapWidth, int bitmapHeight, Rect bounds, Rect outRect) {
GravityCompat.apply(gravity, bitmapWidth, bitmapHeight, bounds, outRect, 0);
}
}
複製代碼
不難發現,DefaultRoundedBitmapDrawable 繼承至 RoundedBitmapDrawable,而且 DefaultRoundedBitmapDrawable 構造方法實際上調用的是 RoundedBitmapDrawable 的構造方法。
RoundedBitmapDrawable(Resources res, Bitmap bitmap) {
if (res != null) {
// 獲取屏幕密度
this.mTargetDensity = res.getDisplayMetrics().densityDpi;
}
this.mBitmap = bitmap;
if (this.mBitmap != null) {
// 計算 Bitmap 的 Width、Height
this.computeBitmapSize();
// 初始化 BitmapShader,今天主角終於出現了
this.mBitmapShader = new BitmapShader(this.mBitmap, TileMode.CLAMP, TileMode.CLAMP);
} else {
this.mBitmapWidth = this.mBitmapHeight = -1;
this.mBitmapShader = null;
}
}
//computeBitmapSize
private void computeBitmapSize() {
this.mBitmapWidth = this.mBitmap.getScaledWidth(this.mTargetDensity);
this.mBitmapHeight = this.mBitmap.getScaledHeight(this.mTargetDensity);
}
複製代碼
在 RoundedBitmapDrawable 的構造方法裏,首先獲取到屏幕的密度,其次獲取傳入的 Bitmap 的寬、高,最後初始化 BitmapShader。其實到這裏就能夠結束了,由於 RoundedBitmapDrawable 實現圓角的方式已經很明瞭了——經過給 Paint 設置 BitmapShader。固然,這是對於那些已經熟練掌握自定義控件的人說的,若是你對自定義控件不熟悉,那就接着往下看吧。
public void draw(@NonNull Canvas canvas) {
Bitmap bitmap = this.mBitmap;
if (bitmap != null) {
this.updateDstRect();
if (this.mPaint.getShader() == null) {
canvas.drawBitmap(bitmap, (Rect)null, this.mDstRect, this.mPaint);
} else {
canvas.drawRoundRect(this.mDstRectF, this.mCornerRadius, this.mCornerRadius, this.mPaint);
}
}
}
複製代碼
在 RoundedBitmapDrawable 的 draw 方法中,首先調用了 updateDstRect() 方法,而後再根據 BitmapShader 是否爲 null 決定究竟是直接繪製 Bitmap(canvas.drawBitmap),仍是繪製圓角矩形(canvas.drawRoundRect)。
void updateDstRect() {
//默認狀況下,該屬性爲 true
if (this.mApplyGravity) {
//是否爲圓形
if (this.mIsCircular) {
//1. 圓形
//計算 Bitmap 短邊
int minDimen = Math.min(this.mBitmapWidth, this.mBitmapHeight);
//爲 mDstRect 設置 Width、Height 屬性
this.gravityCompatApply(this.mGravity, minDimen, minDimen, this.getBounds(), this.mDstRect);
//計算 mDstRect 短邊
int minDrawDimen = Math.min(this.mDstRect.width(), this.mDstRect.height());
//比較 mDstRect 的短邊與 mDstRect Width、Height 的關係,進而縮放 mDstRect,以使 mDstRect 爲正方形
int insetX = Math.max(0, (this.mDstRect.width() - minDrawDimen) / 2);
int insetY = Math.max(0, (this.mDstRect.height() - minDrawDimen) / 2);
this.mDstRect.inset(insetX, insetY);
//肯定圓角的半徑
this.mCornerRadius = 0.5F * (float)minDrawDimen;
} else {
//2. 矩形
//爲 mDstRect 設置 Width、Height 屬性
this.gravityCompatApply(this.mGravity, this.mBitmapWidth, this.mBitmapHeight, this.getBounds(), this.mDstRect);
}
this.mDstRectF.set(this.mDstRect);
if (this.mBitmapShader != null) {
//經過 BitmapShader 對應的 Matrix 使 BitmapShader 中的 Bitmap 從 mDstRectF 左上放開始繪製
this.mShaderMatrix.setTranslate(this.mDstRectF.left, this.mDstRectF.top);
//將 BitmapShader 中的 Bitmap 縮放至與 mDstRectF 尺寸同樣
this.mShaderMatrix.preScale(this.mDstRectF.width() / (float)this.mBitmap.getWidth(), this.mDstRectF.height() / (float)this.mBitmap.getHeight());
this.mBitmapShader.setLocalMatrix(this.mShaderMatrix);
//爲 Paint 設置 BitmapShader
this.mPaint.setShader(this.mBitmapShader);
}
this.mApplyGravity = false;
}
}
複製代碼
註釋已經寫的很清楚了,updateDstRect 方法其實主要就是幹三件事:
下面是我測試的時候打的斷點的截圖:
其中用 一、2 標示的地方是計算 RoundedBitmapDrawable 所在 DstRectF 的 Width、Height 屬性,用 3 標出的地方爲當 RoundedBitmapDrawable 爲圓形時,計算出來的矩形(確切地說,應該是正方形)圓角的半徑。剩下的另外兩個步驟已經在代碼中註釋的很明顯了,我就不贅述了。
public void draw(@NonNull Canvas canvas) {
Bitmap bitmap = this.mBitmap;
if (bitmap != null) {
this.updateDstRect();
if (this.mPaint.getShader() == null) {
canvas.drawBitmap(bitmap, (Rect)null, this.mDstRect, this.mPaint);
} else {
canvas.drawRoundRect(this.mDstRectF, this.mCornerRadius, this.mCornerRadius, this.mPaint);
}
}
}
複製代碼
由於 BitmapShader 不爲 null,因此進入 drawRoundRect 方法。
由於 mCornerRadius 爲 mDstRectF 短邊的一半,因此就有了下面兩張圖:
在使用 RoundedBitmapDrawable 的時候,須要注意地方有:
其實在分析 RoundedBitmapDrawable 實現原理的時候,就說過,若是 Bitmap 的 Width、Height 與 RoundedBitmapDrawable 所在 RectF 的 Width、Height 不一致的時候,會被強制縮放。
以下圖所示:
解決的方法其實也簡單,只須要在向 RoundedBitmapDrawableFactory.create(@NonNull Resources res, @Nullable Bitmap bitmap) 方法傳入 Bitmap 以前判斷 Bitmap 的是否爲正方形。若是不是正方形,則手動從 Bitmap 中截取一個正方形;若是是正方形,則直接將 Bitmap 傳遞給 RoundedBitmapDrawableFactory.create(@NonNull Resources res, @Nullable Bitmap bitmap) 方法。
//根據傳入的 Bitmap 的短邊將 Bitmap 轉換成正方形
public static Bitmap transferToSquareBitmap(Bitmap bitmap) {
if (bitmap == null) {
return null;
}
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
int squareSideLength = Math.min(bitmapWidth, bitmapHeight);
Bitmap squareBitmap = Bitmap.createBitmap(squareSideLength, squareSideLength, Bitmap.Config.ARGB_8888);
int squareBitmapWidth = squareBitmap.getWidth();
int squareBitmapHeight = squareBitmap.getHeight();
int deltaX, deltaY;
if(bitmapWidth > squareBitmapWidth){
deltaX = - (bitmapWidth - squareBitmapWidth)/2;
}else {
deltaX = (bitmapWidth - squareBitmapWidth)/2;
}
if(bitmapHeight > squareBitmapHeight){
deltaY = - (bitmapHeight/2 - squareBitmapHeight/2);
}else {
deltaY = (bitmapHeight/2 - squareBitmapHeight/2);
}
Canvas squareCanvas = new Canvas(squareBitmap);
squareCanvas.drawBitmap(bitmap, deltaX, deltaY, null);
return squareBitmap;
}
複製代碼
//第一步
Bitmap circleBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tiger);
//將 Bitmap 轉換成正方形
circleBitmap = BitmapUtils.transferToSquareBitmap(circleBitmap);
RoundedBitmapDrawable circleDrawable = RoundedBitmapDrawableFactory.create(getResources(), circleBitmap);
//第二步
circleDrawable.setCircular(true);
//第三步
mCircleFitCenterView.setImageDrawable(circleDrawable);
複製代碼
最終效果以下:
接下來分別對下面四種狀況,展開討論:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<!--android:scaleType="fitCenter"-->
<ImageView
android:id="@+id/rounded_bitmap_drawable_circle_fit_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_small"
android:background="@color/white"
android:scaleType="fitCenter"
android:src="@drawable/tiger"
/>
<!--android:scaleType="centerCrop"-->
<ImageView
android:id="@+id/rounded_bitmap_drawable_circle_center_crop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_small"
android:background="@color/white"
android:scaleType="centerCrop"
android:src="@drawable/tiger"/>
</LinearLayout>
</ScrollView>
複製代碼
public class RoundedBitmapDrawableTutorialActivity extends AppCompatActivity {
private ImageView mCircleFitCenterView, mCircleCenterCropView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rounded_bitmap_drawable_tutorial);
initView();
initData();
}
private void initView(){
mCircleFitCenterView = findViewById(R.id.rounded_bitmap_drawable_circle_fit_center);
mCircleCenterCropView = findViewById(R.id.rounded_bitmap_drawable_circle_center_crop);
}
private void initData(){
//第一步
RoundedBitmapDrawable circleDrawable = RoundedBitmapDrawableFactory.create(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.tiger));
//第二步
circleDrawable.setCircular(true);
//第三步
mCircleFitCenterView.setImageDrawable(circleDrawable);
mCircleCenterCropView.setImageDrawable(circleDrawable);
}
}
複製代碼
最終效果以下:
因爲此時兩者效果同樣,因此,我就把圖拉到了兩者的中間,所以,你們看到的是兩個老虎的半張臉。
結論:當 RoundedBitmapDrawable 爲圓形時,ImageView 的 scaleType 不爲 fitCenter 時,沒有「不良反應」。
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<!--android:scaleType="fitCenter"-->
<ImageView
android:id="@+id/rounded_bitmap_drawable_round_rectangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_small"
android:background="@color/white"
android:scaleType="fitCenter"
android:src="@drawable/tiger"/>
<!--android:scaleType="centerCrop"-->
<ImageView
android:id="@+id/rounded_bitmap_drawable_round_rectangle_center_crop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_small"
android:background="@color/white"
android:scaleType="centerCrop"
android:src="@drawable/tiger"/>
</LinearLayout>
</ScrollView>
複製代碼
public class RoundedBitmapDrawableTutorialActivity extends AppCompatActivity {
private ImageView mRoundRectangleView, mRoundRectangleCenterCropView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rounded_bitmap_drawable_tutorial);
initView();
initData();
}
private void initView(){
mRoundRectangleView = findViewById(R.id.rounded_bitmap_drawable_round_rectangle);
mRoundRectangleCenterCropView = findViewById(R.id.rounded_bitmap_drawable_round_rectangle_center_crop);
}
private void initData(){
Bitmap roundRectangleBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tiger);
//第一步
RoundedBitmapDrawable roundRectangleDrawable = RoundedBitmapDrawableFactory.create(getResources(), roundRectangleBitmap);
//第二步
roundRectangleDrawable.setCornerRadius((mViewWidth < mViewHeight ? mViewWidth : mViewHeight)/32);
//第三步
mRoundRectangleView.setImageDrawable(roundRectangleDrawable);
mRoundRectangleCenterCropView.setImageDrawable(roundRectangleDrawable);
}
}
複製代碼
最終效果以下:
由上圖可知,scaleType 爲 fitCenter 的 ImageView 圓角正常顯示,而 scaleType 爲 centerCrop 的 ImageView 圓角未正常顯示。
緣由其實很簡單,由於當 ImageView scaleType 爲 centerCrop 時,當 Drawable 尺寸比 ImageView 尺寸大時,Drawable 短邊將縮小至與 ImageView 對應邊相等,Drawable 長邊根據相應的縮放係數進行縮放,以後將 Drawable 中間顯示在 ImageView 中間;當 Drawable 尺寸比 ImageView 尺寸小時,Drawable 短邊放大至與 ImageView 對應邊相等,Drawable 長邊根據相應的縮放係數進行縮放,以後將 Drawable 中間顯示在 ImageView 中間。
由上圖中 scaleType 爲 fitCenter 的 ImageView 顯示效果可知,轉換以後的 Drawable 尺寸比 ImageView 尺寸小,所以此時會將 Drawable 短邊放大至與 ImageView 對應邊相等、長邊根據相應的縮放係數進行縮放。也就是說,不是 Drawable 未被轉換成圓角,而是 Drawable 的圓角超出了 Drawable 所在 ImageView 的顯示範圍。
驗證這個結論到底正不正確其實也很簡單,只用將 ImageView 的 scaleType 設置爲能知足下面條件的:
當 Drawable 尺寸比 ImageView 尺寸小時,Drawable 不進行任何處理,直接顯示在 ImageView 中間。
而 CENTER_INSIDE 恰好知足此條件。
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<!--android:scaleType="fitCenter"-->
<ImageView
android:id="@+id/rounded_bitmap_drawable_round_rectangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_small"
android:background="@color/white"
android:scaleType="fitCenter"
android:src="@drawable/tiger" />
<!--android:scaleType="centerInside"-->
<ImageView
android:id="@+id/rounded_bitmap_drawable_round_rectangle_center_crop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_small"
android:background="@color/white"
android:scaleType="centerInside"
android:src="@drawable/tiger" />
</LinearLayout>
</ScrollView>
複製代碼
最終效果以下:
將 ImageView 的 scaleType 設置爲 centerInside 以後,第二個 ImageView 的圓角又回來了,成功驗證上面的猜測。
對 ImageView scaleType 屬性不瞭解的人能夠看個人另一篇文章:
這一次,完全幫你搞明白 ImageView ScaleType
說了這麼多了,想必你們都已經掌握如何自定義圓角頭像了,接下來,咱們將 RoundedBitmapDrawable 封裝成一個工具類,這樣在後面使用的時候,就能夠直接拿來用了。
首先,要能區分目標 Drawable 是圓形仍是矩形,所以,有了用於區分 Drawable 形狀的泛型類:
public enum DrawableShape {
CIRCLE,
RECTANGLE
}
複製代碼
其次,要能自定義轉換以後的 Drawable 的尺寸,另外,若是是矩形,還能定義矩形圓角的半徑。因而有了下面這個類:
public class RoundedBitmapDrawableUtils {
public static Drawable getRoundedDrawable(Context context, Bitmap bitmap, DrawableShape drawableShape, float newWidth, float newHeight, float cornerRadius) {
if (bitmap == null) {
return null;
}
if(drawableShape == null){
drawableShape = DrawableShape.CIRCLE;
}
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
if(newWidth != 0 && newHeight != 0){
float scaleRatio = 0;
if(Math.min(bitmapWidth, bitmapHeight) > Math.min(newWidth, newHeight)){
scaleRatio = Math.min(newWidth, newHeight) / Math.min(bitmapWidth, bitmapHeight);
}else if(Math.min(bitmapWidth, bitmapHeight) <= Math.min(newWidth, newHeight)){
scaleRatio = Math.min(newWidth, newHeight) / Math.min(bitmapWidth, bitmapHeight);
}
Matrix matrix = new Matrix();
matrix.postScale(scaleRatio, scaleRatio);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, false);
bitmapWidth = bitmap.getWidth();
bitmapHeight = bitmap.getHeight();
}
Bitmap dstBitmap;
int dstBitmapWidth, dstBitmapHeight;
int deltaX, deltaY;
Canvas dstCanvas;
RoundedBitmapDrawable dstDrawable = null;
switch (drawableShape){
case CIRCLE:
dstBitmap = Bitmap.createBitmap(Math.min(bitmapWidth, bitmapHeight), Math.min(bitmapWidth, bitmapHeight), Bitmap.Config.ARGB_8888);
dstBitmapWidth = dstBitmap.getWidth();
dstBitmapHeight = dstBitmap.getHeight();
if(bitmapWidth > dstBitmapWidth){
deltaX = - (bitmapWidth/2 - dstBitmapWidth/2);
}else {
deltaX = (bitmapWidth/2 - dstBitmapWidth/2);
}
if(bitmapHeight > dstBitmapHeight){
deltaY = - (bitmapHeight/2 - dstBitmapHeight/2);
}else {
deltaY = (bitmapHeight/2 - dstBitmapHeight/2);
}
dstCanvas = new Canvas(dstBitmap);
dstCanvas.drawBitmap(bitmap, deltaX, deltaY, null);
dstDrawable = RoundedBitmapDrawableFactory.create(context.getResources(), dstBitmap);
dstDrawable.setCircular(true);
break;
case RECTANGLE:
dstBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
dstBitmapWidth = dstBitmap.getWidth();
dstBitmapHeight = dstBitmap.getHeight();
if(bitmapWidth > dstBitmapWidth){
deltaX = - (bitmapWidth/2 - dstBitmapWidth/2);
}else {
deltaX = (bitmapWidth/2 - dstBitmapWidth/2);
}
if(bitmapHeight > dstBitmapHeight){
deltaY = - (bitmapHeight/2 - dstBitmapHeight/2);
}else {
deltaY = (bitmapHeight/2 - dstBitmapHeight/2);
}
dstCanvas = new Canvas(dstBitmap);
dstCanvas.drawBitmap(bitmap, deltaX, deltaY, null);
dstDrawable = RoundedBitmapDrawableFactory.create(context.getResources(), dstBitmap);
dstDrawable.setCornerRadius(cornerRadius);
break;
}
return dstDrawable;
}
}
複製代碼
只能傳 Bitmap?!侷限是否是有點大?立刻改一下:
public class RoundedBitmapDrawableUtils {
public static Drawable getRoundedDrawable(Context context, String pathName, DrawableShape drawableShape, float newWidth, float newHeight, float cornerRadius){
return getRoundedDrawable(context, BitmapFactory.decodeFile(pathName), drawableShape, newWidth, newHeight, cornerRadius);
}
public static Drawable getRoundedDrawable(Context context, int id, DrawableShape drawableShape, float newWidth, float newHeight, float cornerRadius){
return getRoundedDrawable(context, BitmapFactory.decodeResource(context.getResources(), id), drawableShape, newWidth, newHeight, cornerRadius);
}
public static Drawable getRoundedDrawable(Context context, InputStream is, DrawableShape drawableShape, float newWidth, float newHeight, float cornerRadius){
return getRoundedDrawable(context, BitmapFactory.decodeStream(is), drawableShape, newWidth, newHeight, cornerRadius);
}
public static Drawable getRoundedDrawable(Context context, Bitmap bitmap, DrawableShape drawableShape, float newWidth, float newHeight, float cornerRadius) {
if (bitmap == null) {
return null;
}
if(drawableShape == null){
drawableShape = DrawableShape.CIRCLE;
}
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
if(newWidth != 0 && newHeight != 0){
float scaleRatio = 0;
if(Math.min(bitmapWidth, bitmapHeight) > Math.min(newWidth, newHeight)){
scaleRatio = Math.min(newWidth, newHeight) / Math.min(bitmapWidth, bitmapHeight);
}else if(Math.min(bitmapWidth, bitmapHeight) <= Math.min(newWidth, newHeight)){
scaleRatio = Math.min(newWidth, newHeight) / Math.min(bitmapWidth, bitmapHeight);
}
Matrix matrix = new Matrix();
matrix.postScale(scaleRatio, scaleRatio);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, false);
bitmapWidth = bitmap.getWidth();
bitmapHeight = bitmap.getHeight();
}
Bitmap dstBitmap;
int dstBitmapWidth, dstBitmapHeight;
int deltaX, deltaY;
Canvas dstCanvas;
RoundedBitmapDrawable dstDrawable = null;
switch (drawableShape){
case CIRCLE:
dstBitmap = Bitmap.createBitmap(Math.min(bitmapWidth, bitmapHeight), Math.min(bitmapWidth, bitmapHeight), Bitmap.Config.ARGB_8888);
dstBitmapWidth = dstBitmap.getWidth();
dstBitmapHeight = dstBitmap.getHeight();
if(bitmapWidth > dstBitmapWidth){
deltaX = - (bitmapWidth/2 - dstBitmapWidth/2);
}else {
deltaX = (bitmapWidth/2 - dstBitmapWidth/2);
}
if(bitmapHeight > dstBitmapHeight){
deltaY = - (bitmapHeight/2 - dstBitmapHeight/2);
}else {
deltaY = (bitmapHeight/2 - dstBitmapHeight/2);
}
dstCanvas = new Canvas(dstBitmap);
dstCanvas.drawBitmap(bitmap, deltaX, deltaY, null);
dstDrawable = RoundedBitmapDrawableFactory.create(context.getResources(), dstBitmap);
dstDrawable.setCircular(true);
break;
case RECTANGLE:
dstBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
dstBitmapWidth = dstBitmap.getWidth();
dstBitmapHeight = dstBitmap.getHeight();
if(bitmapWidth > dstBitmapWidth){
deltaX = - (bitmapWidth/2 - dstBitmapWidth/2);
}else {
deltaX = (bitmapWidth/2 - dstBitmapWidth/2);
}
if(bitmapHeight > dstBitmapHeight){
deltaY = - (bitmapHeight/2 - dstBitmapHeight/2);
}else {
deltaY = (bitmapHeight/2 - dstBitmapHeight/2);
}
dstCanvas = new Canvas(dstBitmap);
dstCanvas.drawBitmap(bitmap, deltaX, deltaY, null);
dstDrawable = RoundedBitmapDrawableFactory.create(context.getResources(), dstBitmap);
dstDrawable.setCornerRadius(cornerRadius);
break;
}
return dstDrawable;
}
}
複製代碼
趕忙試試?
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/rounded_bitmap_drawable_circle_fit_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_small"
android:background="@color/white"
android:scaleType="fitCenter"
android:src="@drawable/tiger" />
<ImageView
android:id="@+id/rounded_bitmap_drawable_round_rectangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_small"
android:background="@color/white"
android:scaleType="fitCenter"
android:src="@drawable/tiger" />
</LinearLayout>
</ScrollView>
複製代碼
public class RoundedBitmapDrawableTutorialActivity extends AppCompatActivity {
private int mScreenWidth, mScreenHeight, mViewWidth, mViewHeight;
private ImageView mCircleFitCenterView, mRoundRectangleView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rounded_bitmap_drawable_tutorial);
getScreenProperty();
initView();
initData();
}
private void getScreenProperty(){
mScreenWidth = DisplayMetricsUtil.getScreenWidth(this);
mScreenHeight = DisplayMetricsUtil.getScreenHeight(this);
mViewWidth = mScreenWidth * 2/3;
mViewHeight = mScreenHeight * 2/3;
}
private void initView(){
mCircleFitCenterView = findViewById(R.id.rounded_bitmap_drawable_circle_fit_center);
mRoundRectangleView = findViewById(R.id.rounded_bitmap_drawable_round_rectangle);
}
private void initData(){
mCircleFitCenterView.setImageDrawable(RoundedBitmapDrawableUtils.getRoundedDrawable(this, BitmapFactory.decodeResource(getResources(), R.drawable.tiger), DrawableShape.CIRCLE, 0, 0, 0));
mRoundRectangleView.setImageDrawable(RoundedBitmapDrawableUtils.getRoundedDrawable(this, BitmapFactory.decodeResource(getResources(), R.drawable.tiger), DrawableShape.RECTANGLE, mViewWidth, mViewHeight, (mViewWidth < mViewHeight ? mViewWidth : mViewHeight)/32));
}
}
複製代碼
最終效果以下:
還在等什麼,趕忙去試試吧。