Android自定義View實(shí)現(xiàn)圓形切圖效果
使用自定義View實(shí)現(xiàn)圓形ImageView的效果,具體內(nèi)容如下

目前圓形邊框還需要調(diào)整,這里有點(diǎn)問(wèn)題
實(shí)現(xiàn)思路
使用一個(gè)Paint,將得到的Bitmap設(shè)置成paint的Shader,設(shè)置完成后,使用Matrix調(diào)整圖片至居中,使用RectF約束邊框,最后完成繪制
初始化Paint,設(shè)置Shader
private void init() {
getBitmapFromDrawable();
if (mBitmap == null) {
return;
}
mShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// bitmap paint
mFillPaint = new Paint();
mFillPaint.setAntiAlias(true);
mFillPaint.setStyle(Paint.Style.FILL);
mFillPaint.setShader(mShader);
// border paint
mBoundPaint = new Paint();
mBoundPaint.setAntiAlias(true);
mBoundPaint.setStyle(Paint.Style.STROKE);
mBoundPaint.setStrokeWidth(mBorderWidth);
mBoundPaint.setColor(mBorderColor);
// border rectF
mBorderBound.set(calculateBitmapBound());
// bitmap rectF
mBitmapBound.set(calculateBitmapBound());
mBitmapBound.inset(mBorderWidth - 10, mBorderWidth - 10);
updateShaderMatrix();
}
獲取Drawable
private Bitmap getBitmapFromDrawable() {
Drawable drawable = getDrawable();
if (drawable instanceof BitmapDrawable) {
mBitmap = ((BitmapDrawable) drawable).getBitmap();
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
return mBitmap;
}
return null;
}
計(jì)算邊距
/**
* 計(jì)算Bitmap邊距
*/
private RectF calculateBitmapBound() {
int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
int sideLength = Math.min(availableWidth, availableHeight); // 可用的直徑
mRadius = sideLength / 2;
int left = getPaddingLeft() + (availableWidth - sideLength) / 2;
int top = getPaddingTop() + (availableHeight - sideLength) / 2;
Log.d(TAG, "calculateBitmapBound: left >>> " + left + " top >>> " + top + " right >>> "
+ (left + sideLength) + " right >>> " + top + " bottom >>> " + (top + sideLength));
return new RectF(left, top, left + sideLength, top + sideLength);
}
調(diào)整Matrix,防止只顯示圖片邊角
/**
* 調(diào)整圖片縮放,目前只支持CenterCrop
*/
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
// 調(diào)整縮放,使圖片居中
if (mBitmapWidth * mBitmapBound.height() > mBitmapBound.width() * mBitmapHeight) {
scale = mBitmapBound.height() / (float) mBitmapHeight;
dx = (mBitmapBound.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mBitmapBound.width() / (float) mBitmapWidth;
dy = (mBitmapBound.height() - mBitmapHeight * scale) * 0.5f;
}
Log.d(TAG, "updateShaderMatrix: scale >>> " + scale);
mShaderMatrix.setScale(scale, scale);
// TODO: 16-10-15 http://chroya.iteye.com/blog/713869
// 回到中心點(diǎn),便于下次縮放
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBitmapBound.left, (int) (dy + 0.5f) + mBitmapBound.top);
mShader.setLocalMatrix(mShaderMatrix);
}
onDraw
@Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
super.onDraw(canvas);
}
Log.d(TAG, "onDraw: centerX >>> " + mBitmapBound.centerX() + " centerY >>> " + mBitmapBound.centerY());
canvas.drawCircle(mBitmapBound.centerX(), mBitmapBound.centerY(), mRadius, mFillPaint);
// 繪制邊框
canvas.drawCircle(mBorderBound.centerX(), mBorderBound.centerY(), mRadius, mBoundPaint);
}
完整代碼
/**
* Created by shixi_tianrui1 on 16-10-7.
* 顯示圓形圖片的ImageView
*/
public class CircleImageView extends ImageView {
private static final String TAG = "LOGGER";
private BitmapShader mShader;
private Paint mFillPaint; // 繪圖
private Paint mBoundPaint; // 繪制圓邊
private Bitmap mBitmap;
private Drawable mDrawable;
private int mBorderColor; // 邊框顏色
private float mBorderWidth; // 邊框?qū)挾?
private RectF mBorderBound = new RectF();
private RectF mBitmapBound = new RectF();
private Matrix mShaderMatrix = new Matrix();
private int mRadius;
private int mBitmapWidth;
private int mBitmapHeight;
private static final float DEFAULT_BORDER_WIDTH = 5;
public CircleImageView(Context context) {
this(context, null);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = getResources().obtainAttributes(attrs, R.styleable.CircleImageView);
mBorderColor = a.getColor(R.styleable.CircleImageView_borderColor, Color.BLUE);
mBorderWidth = a.getDimension(R.styleable.CircleImageView_borderWidth, DEFAULT_BORDER_WIDTH);
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_borderWidth, 20);
a.recycle();
}
private void init() {
getBitmapFromDrawable();
if (mBitmap == null) {
return;
}
mShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// bitmap paint
mFillPaint = new Paint();
mFillPaint.setAntiAlias(true);
mFillPaint.setStyle(Paint.Style.FILL);
mFillPaint.setShader(mShader);
// border paint
mBoundPaint = new Paint();
mBoundPaint.setAntiAlias(true);
mBoundPaint.setStyle(Paint.Style.STROKE);
mBoundPaint.setStrokeWidth(mBorderWidth);
mBoundPaint.setColor(mBorderColor);
// border rectF
mBorderBound.set(calculateBitmapBound());
// bitmap rectF
mBitmapBound.set(calculateBitmapBound());
mBitmapBound.inset(mBorderWidth - 10, mBorderWidth - 10);
updateShaderMatrix();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
init();
}
/**
* 計(jì)算Bitmap邊距
*/
private RectF calculateBitmapBound() {
int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
int sideLength = Math.min(availableWidth, availableHeight); // 可用的直徑
mRadius = sideLength / 2;
int left = getPaddingLeft() + (availableWidth - sideLength) / 2;
int top = getPaddingTop() + (availableHeight - sideLength) / 2;
Log.d(TAG, "calculateBitmapBound: left >>> " + left + " top >>> " + top + " right >>> "
+ (left + sideLength) + " right >>> " + top + " bottom >>> " + (top + sideLength));
return new RectF(left, top, left + sideLength, top + sideLength);
}
private Bitmap getBitmapFromDrawable() {
Drawable drawable = getDrawable();
if (drawable instanceof BitmapDrawable) {
mBitmap = ((BitmapDrawable) drawable).getBitmap();
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
return mBitmap;
}
return null;
}
@Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
super.onDraw(canvas);
}
Log.d(TAG, "onDraw: centerX >>> " + mBitmapBound.centerX() + " centerY >>> " + mBitmapBound.centerY());
canvas.drawCircle(mBitmapBound.centerX(), mBitmapBound.centerY(), mRadius, mFillPaint);
// 繪制邊框
canvas.drawCircle(mBorderBound.centerX(), mBorderBound.centerY(), mRadius, mBoundPaint);
}
/**
* 調(diào)整圖片縮放,目前只支持CenterCrop
*/
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
// 調(diào)整縮放,使圖片居中
if (mBitmapWidth * mBitmapBound.height() > mBitmapBound.width() * mBitmapHeight) {
scale = mBitmapBound.height() / (float) mBitmapHeight;
dx = (mBitmapBound.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mBitmapBound.width() / (float) mBitmapWidth;
dy = (mBitmapBound.height() - mBitmapHeight * scale) * 0.5f;
}
Log.d(TAG, "updateShaderMatrix: scale >>> " + scale);
mShaderMatrix.setScale(scale, scale);
// TODO: 16-10-15 http://chroya.iteye.com/blog/713869
// 回到中心點(diǎn),便于下次縮放
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBitmapBound.left, (int) (dy + 0.5f) + mBitmapBound.top);
mShader.setLocalMatrix(mShaderMatrix);
}
}
目前仍有點(diǎn)問(wèn)題,解決后會(huì)及時(shí)更新。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)一個(gè)帶粘連效果的LoadingBar
Loading效果相信大家應(yīng)該都實(shí)現(xiàn)過(guò),最近發(fā)現(xiàn)了一個(gè)不錯(cuò)的效果,決定分享給大家,所以下面這篇文章主要給大家介紹了關(guān)于利用Android實(shí)現(xiàn)一個(gè)帶粘連效果的LoadingBar的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-12-12
關(guān)于Android HTML5 audio autoplay無(wú)效問(wèn)題的解決方案
這篇文章主要介紹了關(guān)于Android HTML5 audio autoplay無(wú)效問(wèn)題的解決方案,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09
Android多功能時(shí)鐘開(kāi)發(fā)案例(實(shí)戰(zhàn)篇)
這篇文章主要為大家詳細(xì)介紹了Android多功能時(shí)鐘開(kāi)發(fā)案例,開(kāi)發(fā)了時(shí)鐘、鬧鐘、計(jì)時(shí)器和秒表,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05
Android開(kāi)發(fā)手冊(cè)Chip監(jiān)聽(tīng)及ChipGroup監(jiān)聽(tīng)
這篇文章主要為大家介紹了Android開(kāi)發(fā)手冊(cè)Chip監(jiān)聽(tīng)及ChipGroup監(jiān)聽(tīng),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
深入android中The connection to adb is
本篇文章是對(duì)android中The connection to adb is down的問(wèn)題以及解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
Android動(dòng)態(tài)控制狀態(tài)欄顯示和隱藏
這篇文章主要介紹了Android動(dòng)態(tài)控制狀態(tài)欄顯示和隱藏,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04
Android百度地圖應(yīng)用之創(chuàng)建顯示地圖
這篇文章主要為大家詳細(xì)介紹了Android百度地圖應(yīng)用之創(chuàng)建顯示地圖,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06

