Android中ImageCropper矩形、圓形 裁剪框的實(shí)現(xiàn)方法
前言
支持圓形裁剪框,裁剪后生成圓形圖案。
代碼基于開源項(xiàng)目修改,github上項(xiàng)目鏈接:https://github.com/shengge/android-crop (本地下載)
還是貼下效果圖:


說一下圓形裁剪實(shí)現(xiàn)部分:
1.UI方面,自定義CircleHighlightView繼承至HighlightView(原有的矩形裁剪框?qū)崿F(xiàn)),直接看draw方法實(shí)現(xiàn)
@Override
protected void draw(Canvas canvas) {
canvas.save();
Path path = new Path();
outlinePaint.setStrokeWidth( outlineWidth);
if(!hasFocus()) {//沒焦點(diǎn)是,直接畫一個(gè)黑色的矩形框
outlinePaint.setColor( Color.BLACK);
canvas.drawRect( drawRect, outlinePaint);
}
else {
Rect viewDrawingRect = new Rect();
viewContext.getDrawingRect( viewDrawingRect);
//已裁剪框drawRect,算出圓的半徑
float radius = (drawRect.right - drawRect.left) / 2;
//添加一個(gè)圓形
path.addCircle( drawRect.left + radius, drawRect.top + radius, radius, Direction.CW);
outlinePaint.setColor( highlightColor);
//裁剪畫布,path之外的區(qū)域,以outsidePaint填充
canvas.clipPath( path, Region.Op.DIFFERENCE);
canvas.drawRect( viewDrawingRect, outsidePaint);
canvas.restore();
//繪制圓上高亮線,這里outlinePaint定義的Paint.Style.STROKE:表示只繪制幾何圖形的輪廓。
canvas.drawPath( path, outlinePaint);
//當(dāng)modifyMode為grow時(shí),繪制handles,也就是那四個(gè)小圓
if(handleMode == HandleMode.Always || (handleMode == HandleMode.Changing && modifyMode == ModifyMode.Grow)) {
drawHandles( canvas);
}
}
}
這里就實(shí)現(xiàn)了畫圓形裁剪框的操作。
2. 響應(yīng)和處理用戶觸摸事件
1). 判斷觸摸點(diǎn)坐標(biāo)與圓的位置
/**
* 根據(jù)x,y坐標(biāo),計(jì)算其與圓的關(guān)系(圓上、圓內(nèi)、圓外)
* @param x
* @param y
* @return
*/
private int getHitOnCircle(float x, float y) {
Rect r = computeLayout();
int retval = GROW_NONE;
final float hysteresis = 20F;
int radius = (r.right - r.left) / 2;
int centerX = r.left + radius;
int centerY = r.top + radius;
//判斷觸摸位置是否在圓上
float ret = (x - centerX) * (x - centerX) + (y - centerY) * (y - centerY);
double rRadius = Math.sqrt( ret);
double gap = Math.abs( rRadius - radius);
if(gap <= hysteresis) {// 圓上。這里由于是繼承至HighlightView(繪制矩形框的)來處理,所以模擬返回了左右上下,而非純圓上,親測可用。你也可以自定義。
if(x < centerX) {// left
retval |= GROW_LEFT_EDGE;
}
else {
retval |= GROW_RIGHT_EDGE;
}
if(y < centerY) {// up
retval |= GROW_TOP_EDGE;
}
else {
retval |= GROW_BOTTOM_EDGE;
}
}
else if(rRadius > radius) {// outside
retval = GROW_NONE;
}
else if(rRadius < radius) {// inside,圓內(nèi)就執(zhí)行move
retval = MOVE;
}
return retval;
}
由于是繼承至HighLightView(矩形框)來實(shí)現(xiàn)的,如果點(diǎn)(x,y)位置圓上,還需判斷其它那個(gè)象限,對應(yīng)矩形的上下左右位置。
2). 移動(dòng)裁剪框
若上一步判斷,觸摸點(diǎn)在圓內(nèi),就會返回MOVE,并處理移動(dòng)過程。
// Grows the cropping rectangle by (dx, dy) in image space
void moveBy(float dx, float dy) {
Rect invalRect = new Rect(drawRect);
//移動(dòng)
cropRect.offset(dx, dy);
// Put the cropping rectangle inside image rectangle
cropRect.offset(
Math.max(0, imageRect.left - cropRect.left),
Math.max(0, imageRect.top - cropRect.top));
cropRect.offset(
Math.min(0, imageRect.right - cropRect.right),
Math.min(0, imageRect.bottom - cropRect.bottom));
drawRect = computeLayout();
invalRect.union(drawRect);
invalRect.inset(-(int) handleRadius, -(int) handleRadius);
viewContext.invalidate(invalRect);
}
移動(dòng)裁剪框并保證其它image圖片顯示范圍內(nèi)。
3). 縮放裁剪框
此過程和上一步類似,將cropRect矩陣進(jìn)行等比縮放即可,這里就細(xì)說了,詳見代碼:HighLightView.growBy(float dx, float dy)
3.將裁剪圖片保存為圓形
/**
* @param bitmap src圖片
* @return
*/
public static Bitmap getCircleBitmap(Bitmap bitmap) {
Bitmap output = Bitmap.createBitmap( bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas( output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect( 0, 0, bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias( true);
paint.setFilterBitmap( true);
paint.setDither( true);
canvas.drawARGB( 0, 0, 0, 0);
paint.setColor( color);
//在畫布上繪制一個(gè)圓
canvas.drawCircle( bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getWidth() / 2, paint);
paint.setXfermode( new PorterDuffXfermode( Mode.SRC_IN));
canvas.drawBitmap( bitmap, rect, rect, paint);
return output;
}
注意:將bitmap保存為file時(shí),格式請選擇png,不然會出現(xiàn)黑色背景。
鑒于水平有限,從小語文就沒學(xué)好,描述比較凌亂,需要深入理解的請閱讀源代碼。
附:另外一個(gè)很好開源項(xiàng)目 https://github.com/edmodo/cropper (本地下載)
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
淺談 Android 7.0 多窗口分屏模式的實(shí)現(xiàn)
這篇文章主要介紹了淺談 Android 7.0 多窗口分屏模式的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Android registerForActivityResult動(dòng)態(tài)申請權(quán)限案例詳解
這篇文章主要介紹了Android registerForActivityResult動(dòng)態(tài)申請權(quán)限案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09
Android編程實(shí)現(xiàn)通話錄音功能的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)通話錄音功能的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android廣播接收機(jī)制實(shí)現(xiàn)錄音功能的操作技巧,需要的朋友可以參考下2017-06-06
Android頂部狀態(tài)欄透明化并釋放空間的兩種實(shí)現(xiàn)方法
這篇文章主要介紹了Android頂部狀態(tài)欄透明化并釋放空間的兩種實(shí)現(xiàn)方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03
Android 快速實(shí)現(xiàn)狀態(tài)欄透明樣式的示例代碼
下面小編就為大家分享一篇Android 快速實(shí)現(xiàn)狀態(tài)欄透明樣式的示例代碼,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01
Android彈出dialog后無法捕捉back鍵的解決方法
這篇文章主要為大家詳細(xì)介紹了Android彈出dialog后無法捕捉back鍵的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09
android監(jiān)控sim卡有沒有服務(wù)示例(sim卡管理)
android監(jiān)聽SIM卡有沒有服務(wù),可以使用android.telephony.PhoneStateListener類來實(shí)現(xiàn),下面是一個(gè)簡單的小例子,大家參考使用吧2014-01-01

