Android自定義View實(shí)現(xiàn)圓形切圖效果
使用自定義View實(shí)現(xiàn)圓形ImageView的效果,具體內(nèi)容如下
目前圓形邊框還需要調(diào)整,這里有點(diǎ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)問題,解決后會(huì)及時(shí)更新。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Kotlin?Flow數(shù)據(jù)流的3種使用場(chǎng)景詳解
這篇文章主要為大家詳細(xì)介紹了Kotlin中Flow數(shù)據(jù)流的幾種使用場(chǎng)景,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-04-04Android?shape與selector標(biāo)簽使用詳解
Android中提供一種xml的方式,讓我們可以自由地定義背景,比較常用的就是shape標(biāo)簽和selector標(biāo)簽,這篇文章主要介紹了Android?shape與selector標(biāo)簽使用,需要的朋友可以參考下2022-05-05android實(shí)現(xiàn)App活動(dòng)定時(shí)自動(dòng)跳轉(zhuǎn)效果
本篇文章主要介紹了android實(shí)現(xiàn)App活動(dòng)定時(shí)自動(dòng)跳轉(zhuǎn)效果,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02Android用Scroller實(shí)現(xiàn)一個(gè)可向上滑動(dòng)的底部導(dǎo)航欄
本篇文章主要介紹了Android用Scroller實(shí)現(xiàn)一個(gè)可上滑的底部導(dǎo)航欄,具有一定的參考價(jià)值,有興趣的小伙伴們可以參考一下2017-07-07Android圖片上傳實(shí)現(xiàn)預(yù)覽效果
這篇文章主要介紹了Android圖片上傳實(shí)現(xiàn)預(yù)覽效果的相關(guān)資料,需要的朋友可以參考下2016-01-01Android中利用動(dòng)態(tài)加載實(shí)現(xiàn)手機(jī)淘寶的節(jié)日特效
這篇文章主要介紹了Android中利用動(dòng)態(tài)加載實(shí)現(xiàn)手機(jī)淘寶的節(jié)日特效,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-12-12基于VSTS的Xamarin.Android持續(xù)集成步驟詳解
這篇文章主要介紹了基于VSTS的Xamarin.Android持續(xù)集成步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04Android轉(zhuǎn)場(chǎng)效果實(shí)現(xiàn)示例淺析
這篇文章主要為大家介紹了Android轉(zhuǎn)場(chǎng)效果實(shí)現(xiàn)示例淺析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02android studio2.3如何編譯動(dòng)態(tài)庫的過程詳解
這篇文章主要給大家介紹了關(guān)于android studio 2.3如何編譯動(dòng)態(tài)庫的過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-08-08