Android中ImageCropper矩形、圓形 裁剪框的實現(xiàn)方法
前言
支持圓形裁剪框,裁剪后生成圓形圖案。
代碼基于開源項目修改,github上項目鏈接:https://github.com/shengge/android-crop (本地下載)
還是貼下效果圖:
說一下圓形裁剪實現(xiàn)部分:
1.UI方面,自定義CircleHighlightView繼承至HighlightView(原有的矩形裁剪框?qū)崿F(xiàn)),直接看draw方法實現(xiàn)
@Override protected void draw(Canvas canvas) { canvas.save(); Path path = new Path(); outlinePaint.setStrokeWidth( outlineWidth); if(!hasFocus()) {//沒焦點是,直接畫一個黑色的矩形框 outlinePaint.setColor( Color.BLACK); canvas.drawRect( drawRect, outlinePaint); } else { Rect viewDrawingRect = new Rect(); viewContext.getDrawingRect( viewDrawingRect); //已裁剪框drawRect,算出圓的半徑 float radius = (drawRect.right - drawRect.left) / 2; //添加一個圓形 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時,繪制handles,也就是那四個小圓 if(handleMode == HandleMode.Always || (handleMode == HandleMode.Changing && modifyMode == ModifyMode.Grow)) { drawHandles( canvas); } } }
這里就實現(xiàn)了畫圓形裁剪框的操作。
2. 響應(yīng)和處理用戶觸摸事件
1). 判斷觸摸點坐標(biāo)與圓的位置
/** * 根據(jù)x,y坐標(biāo),計算其與圓的關(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(矩形框)來實現(xiàn)的,如果點(x,y)位置圓上,還需判斷其它那個象限,對應(yīng)矩形的上下左右位置。
2). 移動裁剪框
若上一步判斷,觸摸點在圓內(nèi),就會返回MOVE,并處理移動過程。
// Grows the cropping rectangle by (dx, dy) in image space void moveBy(float dx, float dy) { Rect invalRect = new Rect(drawRect); //移動 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); }
移動裁剪框并保證其它image圖片顯示范圍內(nèi)。
3). 縮放裁剪框
此過程和上一步類似,將cropRect矩陣進行等比縮放即可,這里就細說了,詳見代碼: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); //在畫布上繪制一個圓 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時,格式請選擇png,不然會出現(xiàn)黑色背景。
鑒于水平有限,從小語文就沒學(xué)好,描述比較凌亂,需要深入理解的請閱讀源代碼。
附:另外一個很好開源項目 https://github.com/edmodo/cropper (本地下載)
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
Android?手寫RecyclerView實現(xiàn)列表加載
這篇文章主要介紹了Android?手寫RecyclerView實現(xiàn)列表加載,涉及到列表的需求,肯定第一時間想到RecyclerView,即便是自定義View,那么RecyclerView也會是首選,為什么會選擇RecyclerView而不是ListView,主要就是RecyclerView的內(nèi)存復(fù)用機制,這也是RecyclerView的核心?2022-08-08Android開發(fā)之InetAddress基礎(chǔ)入門簡介與源碼實例
這篇文章主要介紹了Android開發(fā)之InetAddress基礎(chǔ)入門簡介,需要的朋友可以參考下2020-03-03Android實現(xiàn)熱門標(biāo)簽的流式布局
這篇文章主要介紹了Android實現(xiàn)熱門標(biāo)簽的流式布局的詳細方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2015-12-12分別用ToolBar和自定義導(dǎo)航欄實現(xiàn)沉浸式狀態(tài)欄
本文主要介紹了分別用ToolBar和自定義導(dǎo)航欄實現(xiàn)沉浸式狀態(tài)欄的方法步驟,具有一定的參考價值,下面跟著小編一起來看下吧2017-01-01