Android實現(xiàn)圓角矩形和圓形ImageView的方式
Android中實現(xiàn)圓角矩形和圓形有很多種方式,其中最常見的方法有ImageLoader設(shè)置Option和自定義View。
1.ImageLoader加載圖片
public static DisplayImageOptions getRoundOptions() {
DisplayImageOptions options = new DisplayImageOptions.Builder()
// 是否設(shè)置為圓角,弧度為多少,當(dāng)弧度為90時顯示的是一個圓
.displayer(new RoundedBitmapDisplayer(30))
.build();
return options;
}
ImageLoader.getInstance().displayImage(imageURL, imageView, Options.getRoundOptions());
2.自定義View實現(xiàn)
自定義View實現(xiàn)圓角矩形和圓形也有很多方法,其中最常見的就是利用Xfermode,Shader。本文就是使用BitmapShader實現(xiàn)圓角的繪制。
自定義CircleImageView
•淺談BitmapShader
BitmapShader是Shader的子類,可以通過Paint.setShader(Shader shader)進行設(shè)置,這里我們只關(guān)注BitmapShader,構(gòu)造方法:
mBitmapShader = new BitmapShader(bitmap,TileMode.CLAMP, TileMode.CLAMP);
參數(shù)1:bitmap
參數(shù)2,參數(shù)3:TileMode;
TileMode的取值有三種:
CLAMP 拉伸
REPEAT 重復(fù)
MIRROR 鏡像
重復(fù):就是橫向、縱向不斷重復(fù)這個bitmap
鏡像:橫向不斷翻轉(zhuǎn)重復(fù),縱向不斷翻轉(zhuǎn)重復(fù);
拉伸:重復(fù)圖片最后的那一個像素;橫向的最后一個橫行像素,不斷的重復(fù),縱項的那一列像素,不斷的重復(fù);
現(xiàn)在大概明白了,BitmapShader通過設(shè)置給mPaint,然后用這個mPaint繪圖時,就會根據(jù)你設(shè)置的TileMode,對繪制區(qū)域進行著色。
對于我們的圓角,以及圓形,我們設(shè)置的模式都是CLAMP,但是你會不會會有一個疑問:
view的寬或者高大于我們的bitmap寬或者高豈不是會拉伸?
嗯,我們會為BitmapShader設(shè)置一個matrix,去適當(dāng)?shù)姆糯蠡蛘呖s小圖片,不會讓“ view的寬或者高大于我們的bitmap寬或者高 ”此條件成立的。
•自定義屬性
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CircleImageView"> <attr name="type" format="enum"> <enum name="circle" value="0"/> <enum name="round" value="1"/> </attr> <attr name="round_Radius" format="dimension" /> <attr name="border_width" format="dimension" /> <attr name="border_color" format="color" /> </declare-styleable> </resources>
•獲取自定義屬性
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
// 獲取類型
type = a.getInt(R.styleable.CircleImageView_type, TYPE_CIRCLE);
// 獲取圓角半徑
mRoundRadius = a.getDimensionPixelSize(R.styleable.CircleImageView_round_Radius, DEFAULT_ROUND_RADIUS);
// 獲取邊界的寬度
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH);
// 獲取邊緣的顏色
mBorderColor = a.getColor(R.styleable.CircleImageView_border_color,DEFAULT_BORDER_COLOR);
//調(diào)用 recycle() 回收TypedArray,以便后面重用
a.recycle();
init();
}•onMeasure
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/**
* 如果類型是圓形,則強制改變view的寬高一致,以小值為準(zhǔn)
*/
if (type == TYPE_CIRCLE) {
mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
setMeasuredDimension(mWidth, mWidth);
}
}•設(shè)置初始化參數(shù)
/**
* 作用就是保證第一次執(zhí)行setup函數(shù)里下面代碼要在構(gòu)造函數(shù)執(zhí)行完畢時調(diào)用
*/
private void init() {
//在這里ScaleType被強制設(shè)定為CENTER_CROP,就是將圖片水平垂直居中,進行縮放
super.setScaleType(SCALE_TYPE);
mReady = true;
if (mSetupPending) {
setup();
mSetupPending = false;
}
}
/**
* 這個函數(shù)很關(guān)鍵,進行圖片畫筆和邊界畫筆(Paint)一些重繪參數(shù)初始化:
* 構(gòu)建渲染器BitmapShader用Bitmap來填充繪制區(qū)域,設(shè)置樣式以及內(nèi)外圓半徑計算等,以及調(diào)用updateShaderMatrix()函數(shù)和 invalidate()函數(shù);
*/
private void setup() {
//因為mReady默認值為false,所以第一次進這個函數(shù)的時候if語句為真進入括號體內(nèi)
//設(shè)置mSetupPending為true然后直接返回,后面的代碼并沒有執(zhí)行。
if (!mReady) {
mSetupPending = true;
return;
}
//防止空指針異常
if (mBitmap == null) {
return;
}
// 構(gòu)建渲染器,用mBitmap來填充繪制區(qū)域 ,參數(shù)值代表如果圖片太小的話 就直接拉伸
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// 設(shè)置圖片畫筆反鋸齒
mBitmapPaint.setAntiAlias(true);
// 設(shè)置圖片畫筆渲染器
mBitmapPaint.setShader(mBitmapShader);
// 設(shè)置邊界畫筆樣式
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor);
mBorderPaint.setStrokeWidth(mBorderWidth);
//這個地方是取的原圖片的寬高
mBitmapHeight = mBitmap.getHeight();
mBitmapWidth = mBitmap.getWidth();
//設(shè)置含邊界顯示區(qū)域,取的是CircleImageView的布局實際大小
mBorderRect.set(0, 0, getWidth(), getHeight());
//初始圖片顯示區(qū)域為mBorderRect減去邊緣部分
mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);
//下面計算的值都是為onDraw中畫圖做準(zhǔn)備
if (type == TYPE_CIRCLE) {
//計算 圓形帶邊界部分(外圓)的半徑,取mBorderRect的寬高減去一個邊緣大小的一半的較小值
mBorderRadius = (mBorderRect.width() - mBorderWidth)/2;
//這里計算的是內(nèi)圓的半徑,也即去除邊界寬度的半徑
mDrawableRadius = mDrawableRect.width()/2;
} else if (type == TYPE_ROUND) {
//如果是圓角矩形,重新計算邊緣區(qū)域,使處于邊緣正中央
mBorderRect.set(mBorderWidth/2, mBorderWidth/2, getWidth() - mBorderWidth/2, getHeight() - mBorderWidth/2);
}
//設(shè)置渲染器的變換矩陣也即是mBitmap用何種縮放形式填充
updateShaderMatrix();
//手動觸發(fā)ondraw()函數(shù) 完成最終的繪制
invalidate();
}•設(shè)置渲染器的變換矩陣
/**
* 這個函數(shù)為設(shè)置BitmapShader的Matrix參數(shù),設(shè)置最小縮放比例,平移參數(shù)。
* 作用:保證圖片損失度最小和始終繪制圖片正中央的那部分
*/
private void updateShaderMatrix() {
float scaleX = 1.0f;
float scaleY = 1.0f;
float scale = 1.0f;
float dx = 0;
float dy = 0;
// 如果圖片的寬或者高與view的寬高不匹配,計算出需要縮放的比例;縮放后的圖片的寬高,一定要大于我們view的寬高;所以我們這里取大值
if (type == TYPE_CIRCLE) {
scaleX = mWidth * 1.0f / mBitmapWidth;
scaleY = mWidth * 1.0f / mBitmapHeight;
scale = Math.max(scaleX, scaleY);
} else if (type == TYPE_ROUND) {
scaleX = getWidth() * 1.0f / mBitmapWidth;
scaleY = getHeight() * 1.0f / mBitmapHeight;
scale = Math.max(scaleX, scaleY);
}
if (scaleX > scaleY) {
// x軸縮放 y軸平移 使得圖片的x軸方向的邊的尺寸縮放到圖片顯示區(qū)域(mDrawableRect)一樣)
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
} else {
// y軸縮放 x軸平移 使得圖片的y軸方向的邊的尺寸縮放到圖片顯示區(qū)域(mDrawableRect)一樣)
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
}
mShaderMatrix.set(null);
//縮放
mShaderMatrix.setScale(scale, scale);
// 平移
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth);
// 設(shè)置變換矩陣
mBitmapShader.setLocalMatrix(mShaderMatrix);
}•onDraw
@Override
protected void onDraw(Canvas canvas) {
//如果圖片不存在就不畫
if (getDrawable() == null)
return;
if (type == TYPE_ROUND) {
//繪制內(nèi)圓角矩形,參數(shù)矩形區(qū)域,圓角半徑,圖片畫筆為mBitmapPaint
canvas.drawRoundRect(mDrawableRect, mRoundRadius, mRoundRadius, mBitmapPaint);
if (mBorderWidth != 0) {
//如果圓形邊緣的寬度不為0 我們還要繪制帶邊界的外圓角矩形 參數(shù)矩形區(qū)域,圓角半徑,邊界畫筆為mBorderPaint
canvas.drawRoundRect(mBorderRect , mRoundRadius + mBorderWidth / 2, mRoundRadius + mBorderWidth / 2, mBorderPaint);
}
} else if (type == TYPE_CIRCLE) {
//繪制內(nèi)圓形,參數(shù)圓心坐標(biāo),內(nèi)圓半徑,圖片畫筆為mBitmapPaint
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
//如果圓形邊緣的寬度不為0 我們還要繪制帶邊界的外圓形 參數(shù)圓心坐標(biāo),外圓半徑,邊界畫筆為mBorderPaint
if (mBorderWidth != 0) {
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint);
}
}
}而且,我們給自定義View添加了幾個接口,可以用來直接設(shè)置類型、邊緣顏色、邊緣寬度和圖片信息等。
使用CircleImageView
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:attr="http://schemas.android.com/apk/res/com.hx.circleimageview" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#CDCDC1" android:orientation="vertical" > <com.hx.circleimageview.CircleImageView android:id="@+id/image1" android:layout_width="150dp" android:layout_height="150dp" android:layout_margin="10dp" android:src="@drawable/crazy_1" attr:type="circle" attr:border_color="#FFffffff" attr:border_width="2dp" /> <com.hx.circleimageview.CircleImageView android:id="@+id/image2" android:layout_width="150dp" android:layout_height="150dp" android:layout_margin="10dp" android:src="@drawable/crazy_2" attr:type="round" attr:border_width="2dp" /> <com.hx.circleimageview.CircleImageView android:id="@+id/image3" android:layout_width="250dp" android:layout_height="150dp" android:layout_margin="10dp" android:src="@drawable/crazy_3" attr:type="round" attr:round_Radius="20dp" attr:border_color="#9400D3" attr:border_width="5dp" /> </LinearLayout>
我們在JAVA中對三個ImageView添加點擊事件
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.image1:
image1.setBorderColor(Color.BLACK);
break;
case R.id.image2:
image2.setImageResource(R.drawable.crazy_3);
break;
case R.id.image3:
int type = image3.getType() == CircleImageView.TYPE_CIRCLE ? CircleImageView.TYPE_ROUND : CircleImageView.TYPE_CIRCLE;
image3.setType(type);
break;
}
運行后效果圖如下:

源碼下載:http://xiazai.jb51.net/201609/yuanma/Android-ImageView(jb51.net).rar
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- android 實現(xiàn)圓角圖片解決方案
- Android中TextView顯示圓圈背景或設(shè)置圓角的方法
- Android關(guān)于Glide的使用(高斯模糊、加載監(jiān)聽、圓角圖片)
- Android圖片特效:黑白特效、圓角效果、高斯模糊
- Android開發(fā)使用自定義View將圓角矩形繪制在Canvas上的方法
- Android中實現(xiàn)EditText圓角的方法
- Android中Glide加載圓形圖片和圓角圖片實例代碼
- android 設(shè)置圓角圖片實現(xiàn)代碼
- Android自定義控件之圓形、圓角ImageView
- Android利用Xfermode剪裁圓角
相關(guān)文章
Android彈窗ListPopupWindow的簡單應(yīng)用詳解
這篇文章主要為大家詳細介紹了Android彈窗ListPopupWindow的簡單應(yīng)用,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11
解決Bitmap通過getWidth和getHeight獲取尺寸不符的問題
這篇文章主要介紹了解決Bitmap通過getWidth和getHeight獲取尺寸不符的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
Android巧用DecorView實現(xiàn)對話框功能
本篇文章主要介紹了Android巧用DecorView實現(xiàn)對話框功能,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04
Android 實現(xiàn)全屏和無標(biāo)題欄的顯示
本篇文章主要介紹了Android 全屏顯示和無標(biāo)題欄的方法,并附上代碼實例,和運行效果圖,有需要的朋友可以參考下2016-07-07
百度地圖實現(xiàn)小車規(guī)劃路線后平滑移動功能
這篇文章主要介紹了百度地圖實現(xiàn)小車規(guī)劃路線后平滑移動功能,本文是小編寫的一個demo,通過效果圖展示的非常直白,需要的朋友可以參考下2020-01-01
Android InputMethodManager輸入法簡介
這篇文章主要介紹了Android InputMethodManager輸入法框架的使用,具有參考價值,需要的朋友可以參考下。2016-06-06
Android百度地圖應(yīng)用之創(chuàng)建顯示地圖
這篇文章主要為大家詳細介紹了Android百度地圖應(yīng)用之創(chuàng)建顯示地圖,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-06-06

