Android自定義View實(shí)現(xiàn)照片裁剪框與照片裁剪功能
本文所需要實(shí)現(xiàn)的就是這樣一種有逼格的效果:
右上角加了個(gè)圖片框,按下確定可以裁剪正方形區(qū)域里的圖片并顯示在右上角。
實(shí)現(xiàn)思路:
1:首先需要自定義一個(gè)ZoomImageView來顯示我們需要的圖片,這個(gè)View需要讓圖片能夠以合適的位置展現(xiàn)在當(dāng)前布局的圖片展示區(qū)域內(nèi)(合適的位置值的是:如果圖片長(zhǎng)度大于屏幕,則壓縮圖片長(zhǎng)度至屏幕寬度,高度等比壓縮并居中顯示,如果圖片高度大于屏幕,則壓縮圖片高度至屏幕高度,長(zhǎng)度等比壓縮并居中顯示。);
2:然后需要實(shí)現(xiàn)這個(gè)拖動(dòng)的框框,該框框?qū)崿F(xiàn)的功能有四點(diǎn):拖動(dòng)、擴(kuò)大縮小、觸摸時(shí)顯示基準(zhǔn)線、截圖。
首先是布局設(shè)計(jì)image_details.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <RelativeLayout android:layout_width="match_parent" android:layout_height="55dp" android:background="#323441"> <ImageButton android:id="@+id/certification_returnbtn" android:layout_width="55dp" android:layout_height="55dp" android:background="@android:color/transparent" android:padding="15dp" android:scaleType="fitCenter" android:src="@drawable/topbar_returnbtn"/> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_marginLeft="10dp" android:layout_toRightOf="@id/certification_returnbtn" android:gravity="center_vertical" android:text="裁剪圖片" android:textColor="@android:color/white" android:textSize="20sp"/> <!-- <ImageButton android:layout_width="55dp" android:layout_height="55dp" android:layout_alignParentRight="true" android:layout_marginRight="10dp" android:background="@android:color/transparent" android:padding="16dp" android:scaleType="fitCenter" android:src="@drawable/ic_rotate_24dp"/>--> <ImageView android:id="@+id/testimg" android:layout_alignParentRight="true" android:layout_marginRight="10dp" android:layout_width="55dp" android:layout_height="55dp"/> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <com.whale.nangua.pubuliuzhaopianqiang.ZoomImageView android:id="@+id/zoom_image_view" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#303030"/> <com.whale.nangua.pubuliuzhaopianqiang.ChoiceBorderView android:id="@+id/zoom_choiceborder_view" android:layout_width="match_parent" android:layout_height="match_parent"/> <Button android:id="@+id/image_details_subbtn" android:text="確定" android:background="@drawable/image_details_submitbtn_shape" android:layout_marginBottom="20dp" android:layout_width="180dp" android:layout_height="40dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true"/> </RelativeLayout> </LinearLayout>
布局比較簡(jiǎn)單,兩個(gè)View互相層疊。
自定義圖片大小控制視圖:ZoomImageView.java
代碼注釋很詳細(xì)就不解釋了。
package com.whale.nangua.pubuliuzhaopianqiang; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; /** * Created by nangua on 2016/7/20. */ public class ZoomImageView extends View { /** * 初始化狀態(tài)常量 */ public static final int STATUS_INIT = 1; /** * 用于對(duì)圖片進(jìn)行移動(dòng)和縮放變換的矩陣 */ private Matrix matrix = new Matrix(); /** * 待展示的Bitmap對(duì)象 */ private Bitmap sourceBitmap; /** * 記錄當(dāng)前操作的狀態(tài),可選值為STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE */ private int currentStatus; /** * ZoomImageView控件的寬度 */ private int width; /** * ZoomImageView控件的高度 */ private int height; /** * ZoomImageView構(gòu)造函數(shù),將當(dāng)前操作狀態(tài)設(shè)為STATUS_INIT。 * * @param context * @param attrs */ public ZoomImageView(Context context, AttributeSet attrs) { super(context, attrs); currentStatus = STATUS_INIT; } /** * 將待展示的圖片設(shè)置進(jìn)來。 * * @param bitmap 待展示的Bitmap對(duì)象 */ public void setImageBitmap(Bitmap bitmap) { sourceBitmap = bitmap; invalidate(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (changed) { // 分別獲取到ZoomImageView的寬度和高度 width = getWidth(); height = getHeight(); } } /** * 根據(jù)currentStatus的值來決定對(duì)圖片進(jìn)行什么樣的繪制操作。 */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); initBitmap(canvas); canvas.drawBitmap(sourceBitmap, matrix, null); } float translateY;//Y軸偏移量 float translateX;//X軸偏移量 /** * @param canvas * @autohr nangua * 對(duì)圖片進(jìn)行初始化操作,包括讓圖片居中,以及當(dāng)圖片大于屏幕寬高時(shí)對(duì)圖片進(jìn)行壓縮。 * <p> * 1.當(dāng)圖片寬度大于顯示寬度、圖片高度小于顯示寬度: * 設(shè)置圖片寬度為顯示寬度,高度縮放*(圖片寬度/顯示寬度) * <p> * 2.當(dāng)圖片寬度小于顯示寬度、圖片高度大于顯示寬度: * 設(shè)置圖片高度為顯示高度,寬度縮放*(圖片高度/顯示高 度) * <p> * 3.當(dāng)圖片寬度大于顯示寬度,圖片高度大于顯示寬度: * 選取差度更大的一邊進(jìn)行壓縮,另一邊等比縮放 * <p> * 4.當(dāng)圖片寬度小于顯示寬度,圖片高度小于顯示寬度: * 選取差度更大的一邊進(jìn)行壓縮,另一邊等比縮放 */ private void initBitmap(Canvas canvas) { if (sourceBitmap != null) { matrix.reset(); //重置矩陣 int bitmapWidth = sourceBitmap.getWidth(); //得到源圖片寬 int bitmapHeight = sourceBitmap.getHeight(); //得到源圖片高 //如果原圖片大小大于控件寬高 if (bitmapWidth > width || bitmapHeight > height) { //如果寬和高都比屏幕大,選擇差度大的一邊縮小,另一邊等比縮小 if (bitmapWidth > width && bitmapHeight > height) { int distanceX = Math.abs(width - bitmapWidth); int distanceY = Math.abs(height - bitmapHeight); float ratio; //找出差值大的一邊,進(jìn)行縮小 if (distanceX >= distanceY) { ratio = width / (bitmapWidth * 1.0f); matrix.postScale(ratio, ratio); //此時(shí)橫軸鋪滿,只需要對(duì)豎軸進(jìn)行平移 translateY = (height - sourceBitmap.getHeight() * ratio) / 2f; matrix.postTranslate(0, translateY); } else { ratio = height / (bitmapHeight * 1.0f); matrix.postScale(ratio, ratio); //此時(shí)豎軸鋪滿,只需要對(duì)橫軸進(jìn)行平移 translateX = (width - sourceBitmap.getWidth() * ratio) / 2f; matrix.postTranslate(translateX, 0); //在橫縱軸上進(jìn)行平移 } //當(dāng)圖片寬度大于顯示寬度、圖片高度小于顯示寬度: } else if (bitmapWidth > width) { // 當(dāng)圖片寬度大于屏幕寬度時(shí),將圖片等比例壓縮,使它可以完全顯示出來 float ratio = width / (bitmapWidth * 1.0f); //壓縮比例 matrix.postScale(ratio, ratio); translateY = (height - (bitmapHeight * ratio)) / 2f; // 在縱坐標(biāo)方向上進(jìn)行偏移,以保證圖片居中顯示 matrix.postTranslate(0, translateY); //當(dāng)圖片寬度小于顯示寬度、圖片高度大于顯示寬度: } else if (bitmapHeight > height) { // 當(dāng)圖片高度大于屏幕高度時(shí),將圖片等比例壓縮,使它可以完全顯示出來 float ratio = height / (bitmapHeight * 1.0f); //壓縮比例 matrix.postScale(ratio, ratio); translateX = (width - (bitmapWidth * ratio)) / 2f; // 在橫坐標(biāo)方向上進(jìn)行偏移,以保證圖片居中顯示 matrix.postTranslate(translateX, 0); } } else { // 當(dāng)圖片的寬高都小于屏幕寬高時(shí),選擇差度小的一邊鋪滿,另一邊等比擴(kuò)大 //計(jì)算長(zhǎng)和寬的差值 int distanceX = Math.abs(width - bitmapWidth); int distanceY = Math.abs(height - bitmapHeight); float ratio; //找出差值小的一邊,進(jìn)行擴(kuò)大 if (distanceX <= distanceY) { ratio = width / (bitmapWidth * 1.0f); matrix.postScale(ratio, ratio); //此時(shí)橫軸鋪滿,只需要對(duì)豎軸進(jìn)行平移 translateY = (height - sourceBitmap.getHeight() * ratio) / 2f; matrix.postTranslate(0, translateY); } else { ratio = height / (bitmapHeight * 1.0f); matrix.postScale(ratio, ratio); //此時(shí)豎軸鋪滿,只需要對(duì)橫軸進(jìn)行平移 translateX = (width - sourceBitmap.getWidth() * ratio) / 2f; matrix.postTranslate(translateX, 0); //在橫縱軸上進(jìn)行平移 } } //進(jìn)行繪制 canvas.drawBitmap(sourceBitmap, matrix, null); } } }
重點(diǎn)來了,相冊(cè)選取框視圖:ChoiceBorderView.java
package com.whale.nangua.pubuliuzhaopianqiang; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; /** * 相冊(cè)選擇框的View * Created by nangua on 2016/7/21. */ public class ChoiceBorderView extends View { private int scale = (int) this.getResources().getDisplayMetrics().density; //屏幕像素密度 private float borderHeight; //總高 private float borderWith; //總寬 private float borderLength = 200 * scale; //邊框長(zhǎng)度 private int RECT_BORDER_WITH = 3 * scale; //長(zhǎng)方形框框粗 private int RECT_CORNER_WITH = 6 * scale; //四個(gè)角的粗 private int RECT_CORNER_HEIGHT = 20 * scale; //四個(gè)角的長(zhǎng)度 //四個(gè)點(diǎn)坐標(biāo) private static float[][] four_corner_coordinate_positions; private static int NOW_MOVE_STATE = 1; //移動(dòng)狀態(tài),默認(rèn)為1,Y軸=1,X軸=2 private static boolean MOVE_OR_ZOOM_STATE = true; //移動(dòng)或縮放狀態(tài), true 為移動(dòng) public ChoiceBorderView(Context context, AttributeSet attrs) { super(context, attrs); this.setFocusable(true); this.setFocusableInTouchMode(true); init(); } /** * 初始化布局 * @param changed * @param left * @param top * @param right * @param bottom */ @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); borderHeight = this.getHeight(); borderWith = this.getWidth(); //初始化四個(gè)點(diǎn)的坐標(biāo) four_corner_coordinate_positions = new float[][]{ {(borderWith - borderLength) / 2, (borderHeight - borderLength) / 2}, //左上 {(borderWith + borderLength) / 2, (borderHeight - borderLength) / 2}, //右上 {(borderWith - borderLength) / 2, (borderHeight + borderLength) / 2}, //左下 {(borderWith + borderLength) / 2, (borderHeight + borderLength) / 2}, //右上 }; } private void init() { } private int temp1 = (RECT_CORNER_WITH - RECT_BORDER_WITH) / 2; //長(zhǎng)方形的粗半距 private int temp2 = (RECT_CORNER_WITH + RECT_BORDER_WITH) / 2; //四個(gè)角的粗半距 /** * RECT_CORNER_WITH = 6 * RECT_BORDER_WITH =3 * * @param canvas */ @Override protected void onDraw(Canvas canvas) { Paint paintRect = new Paint(); //初始化畫筆 //畫邊框的畫筆 paintRect.setColor(getResources().getColor(R.color.bordercolor)); //顏色 paintRect.setStrokeWidth(RECT_BORDER_WITH); //寬度 paintRect.setAntiAlias(true); //抗鋸齒 paintRect.setStyle(Paint.Style.STROKE); //設(shè)置空心 canvas.drawRect(four_corner_coordinate_positions[0][0], four_corner_coordinate_positions[0][1], four_corner_coordinate_positions[3][0], four_corner_coordinate_positions[3][1], paintRect); //畫四個(gè)角的畫筆 paintRect.setColor(Color.WHITE); paintRect.setStrokeWidth(RECT_CORNER_WITH); paintRect.setAntiAlias(true); //左上角的兩根 canvas.drawLine(four_corner_coordinate_positions[0][0] - temp2, four_corner_coordinate_positions[0][1] - temp1, four_corner_coordinate_positions[0][0] - temp1 + RECT_CORNER_HEIGHT, four_corner_coordinate_positions[0][1] - temp1, paintRect); canvas.drawLine(four_corner_coordinate_positions[0][0] - temp1, four_corner_coordinate_positions[0][1] - temp2, four_corner_coordinate_positions[0][0] - temp1, four_corner_coordinate_positions[0][1] - temp1 + RECT_CORNER_HEIGHT, paintRect); //左下角的兩根 canvas.drawLine(four_corner_coordinate_positions[2][0] - temp2, four_corner_coordinate_positions[2][1] + temp1, four_corner_coordinate_positions[2][0] - temp1 + RECT_CORNER_HEIGHT, four_corner_coordinate_positions[2][1] + temp1, paintRect); canvas.drawLine(four_corner_coordinate_positions[2][0] - temp1, four_corner_coordinate_positions[2][1] + temp1, four_corner_coordinate_positions[2][0] - temp1, four_corner_coordinate_positions[2][1] + temp1 - RECT_CORNER_HEIGHT, paintRect); //右上角的兩根 canvas.drawLine(four_corner_coordinate_positions[1][0] + temp1, four_corner_coordinate_positions[1][1] - temp1, four_corner_coordinate_positions[1][0] + temp1 - RECT_CORNER_HEIGHT, four_corner_coordinate_positions[1][1] - temp1, paintRect); canvas.drawLine(four_corner_coordinate_positions[1][0] + temp1, four_corner_coordinate_positions[1][1] - temp2, four_corner_coordinate_positions[1][0] + temp1, four_corner_coordinate_positions[1][1] - temp1 + RECT_CORNER_HEIGHT , paintRect); //右下角的兩根 canvas.drawLine(four_corner_coordinate_positions[3][0] + temp2, four_corner_coordinate_positions[3][1] + temp1, four_corner_coordinate_positions[3][0] + temp1 - RECT_CORNER_HEIGHT, four_corner_coordinate_positions[3][1] + temp1, paintRect); canvas.drawLine(four_corner_coordinate_positions[3][0] + temp1, four_corner_coordinate_positions[3][1] + temp1, four_corner_coordinate_positions[3][0] + temp1, four_corner_coordinate_positions[3][1] + temp1 - RECT_CORNER_HEIGHT, paintRect); //畫掃描線 if (IF_SCANNING_SHOW) { paintRect.setColor(Color.WHITE); paintRect.setStrokeWidth(1); paintRect.setAntiAlias(true); paintRect.setStyle(Paint.Style.STROKE); //共四根線 //豎1 canvas.drawLine(four_corner_coordinate_positions[0][0] + borderLength / 3, four_corner_coordinate_positions[0][1] + temp1, four_corner_coordinate_positions[2][0] + borderLength / 3, four_corner_coordinate_positions[2][1] - temp1, paintRect); //豎2 canvas.drawLine(four_corner_coordinate_positions[1][0] - borderLength / 3, four_corner_coordinate_positions[1][1] + temp1, four_corner_coordinate_positions[3][0] - borderLength / 3, four_corner_coordinate_positions[3][1] - temp1, paintRect); //橫1 canvas.drawLine(four_corner_coordinate_positions[0][0] + temp1, four_corner_coordinate_positions[0][1] + borderLength / 3, four_corner_coordinate_positions[1][0] - temp1, four_corner_coordinate_positions[1][1] + borderLength / 3, paintRect); //橫2 canvas.drawLine(four_corner_coordinate_positions[2][0] + temp1, four_corner_coordinate_positions[2][1] - borderLength / 3, four_corner_coordinate_positions[3][0] - temp1, four_corner_coordinate_positions[3][1] - borderLength / 3, paintRect); } } private boolean IF_SCANNING_SHOW = false; private int lastX = 0; //上次按下的X位置 private int lastY = 0; //上次按下的Y位置 private int offsetX = 0; //X軸偏移量 private int offsetY = 0; //Y軸偏移量 static int point = -1;// 用戶按下的點(diǎn) private int POINT_STATE = -1; //判斷用戶是縮小還是放大 0放大 1縮小 @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: IF_SCANNING_SHOW = true;//顯示掃描線 if (isInTheCornerCircle(event.getX(), event.getY()) != -1) { //開始縮放操作 MOVE_OR_ZOOM_STATE = false; //設(shè)置false為縮放狀態(tài) point = isInTheCornerCircle(event.getX(), event.getY()); } lastX = x; lastY = y; invalidate(); break; case MotionEvent.ACTION_MOVE: offsetX = x - lastX; offsetY = y - lastY; //判斷當(dāng)前是擴(kuò)大還是縮小操作 judgementXandY(); //限定移動(dòng)范圍 //移動(dòng)狀態(tài):只有在移動(dòng)狀態(tài)下才能移動(dòng) if (MOVE_OR_ZOOM_STATE) { getoffsetXandoffsetY(); //四個(gè)點(diǎn)的坐標(biāo)信息也要隨之改變 for (int i = 0; i < four_corner_coordinate_positions.length; i++) { four_corner_coordinate_positions[i][0] += offsetX; four_corner_coordinate_positions[i][1] += offsetY; //更新回調(diào)接口 onImageDetailsSizeChanggedl.onBorderSizeChangged( (int) four_corner_coordinate_positions[0][0], (int) four_corner_coordinate_positions[0][1], (int) borderLength ); invalidate(); } // this.scrollBy(-offsetX, -offsetY); //這里棄用,后面改用了四點(diǎn)坐標(biāo)移動(dòng)代替背景移動(dòng) } //在縮放狀態(tài)下 else { //按住某一個(gè)點(diǎn),該點(diǎn)的坐標(biāo)改變,其他2個(gè)點(diǎn)坐標(biāo)跟著改變,對(duì)點(diǎn)坐標(biāo)不變 max = Math.abs(offsetX) >= Math.abs(offsetY) ? Math.abs(offsetX) : Math.abs(offsetY); //只有在擴(kuò)大操作才進(jìn)行邊界范圍判斷 if (POINT_STATE == 0) { getoffsetXandoffsetY(); //邊界范圍判斷 } //縮小操作時(shí)進(jìn)行邊界不能太小判斷 else if (POINT_STATE == 1) { //如果邊長(zhǎng)+max太小,直接返回 if (borderLength - max <= RECT_CORNER_HEIGHT*2-temp2) { max = 0; } } //改變坐標(biāo) changgeFourCoodinatePosition(point, offsetX, offsetY); //更新邊長(zhǎng) notifyNowborderLength(); //更新回調(diào)接口 onImageDetailsSizeChanggedl.onBorderSizeChangged( (int) four_corner_coordinate_positions[0][0], (int) four_corner_coordinate_positions[0][1], (int) borderLength ); invalidate(); } lastX = x; lastY = y; break; case MotionEvent.ACTION_UP: IF_SCANNING_SHOW = false; //不顯示掃描線 MOVE_OR_ZOOM_STATE = true; //回歸為默認(rèn)的移動(dòng)狀態(tài) invalidate(); break; } return true; } /** * 更新矩形框邊長(zhǎng)的方法 */ private void notifyNowborderLength() { float a = four_corner_coordinate_positions[0][0]; float b = four_corner_coordinate_positions[0][1]; float c = four_corner_coordinate_positions[1][0]; float d = four_corner_coordinate_positions[1][1]; float temp1 = (float) Math.pow(a - c, 2); float temp2 = (float) Math.pow(b - d, 2); borderLength = (float) Math.sqrt(temp1 + temp2); } /** * POINT_STATE 為0放大, 1縮小 */ private void judgementXandY() { switch (point) { case 0: if ((offsetX <= 0 && offsetY <= 0) || (offsetX <= 0 && offsetY >= 0)) { POINT_STATE = 0;//擴(kuò)大 } else { POINT_STATE = 1;//縮小 } break; case 1: if ((offsetX >= 0 && offsetY <= 0) || (offsetX >= 0 && offsetY >= 0)) { POINT_STATE = 0; } else { POINT_STATE = 1; } break; case 2: if ((offsetX <= 0 && offsetY >= 0) || (offsetX <= 0 && offsetY <= 0)) { POINT_STATE = 0; } else { POINT_STATE = 1; } break; case 3: if ((offsetX >= 0 && offsetY >= 0) || (offsetX >= 0 && offsetY <= 0)) { POINT_STATE = 0; } else { POINT_STATE = 1; } break; } } /** * 防止X和Y溢出邊界的算法 */ private void getoffsetXandoffsetY() { //如果是移動(dòng)狀態(tài) if (MOVE_OR_ZOOM_STATE) { if ((four_corner_coordinate_positions[0][0] + offsetX <= 0) || (four_corner_coordinate_positions[1][0] + offsetX >= borderWith) ) { offsetX = 0; } if ((four_corner_coordinate_positions[0][1] + offsetY <= 0) || (four_corner_coordinate_positions[2][1] + offsetY >= borderHeight) ) { offsetY = 0; } } //如果是縮放狀態(tài) else { switch (point) { case 0: if ((four_corner_coordinate_positions[0][0] - max <= 0) || (four_corner_coordinate_positions[0][1] - max <= 0) ) { max = 0; } break; case 1: if ((four_corner_coordinate_positions[1][0] + max >= borderWith) || (four_corner_coordinate_positions[1][1] - max <= 0) ) { max = 0; } break; case 2: if ((four_corner_coordinate_positions[2][0] - max <= 0) || (four_corner_coordinate_positions[2][1] + max >= borderHeight) ) { max = 0; } break; case 3: if ((four_corner_coordinate_positions[3][0] + max >= borderWith) || (four_corner_coordinate_positions[3][1] + max >= borderHeight) ) { max = 0; } break; } } } static int max; /** * 擴(kuò)大縮放方法 * 根據(jù)用戶傳來的點(diǎn)改變其他點(diǎn)的坐標(biāo) * 按住某一個(gè)點(diǎn),該點(diǎn)的坐標(biāo)改變,其他2個(gè)點(diǎn)坐標(biāo)跟著改變,對(duì)點(diǎn)坐標(biāo)不變 * 點(diǎn)陣示意: * 0 1 * 2 3 * * @param point 用戶按的點(diǎn) * @param offsetX X軸偏移量 * @param offsetY Y軸偏移量 */ private void changgeFourCoodinatePosition(int point, int offsetX, int offsetY) { switch (point) { case 0: if (offsetX > 0 && offsetY < 0) { //變化0點(diǎn)的位置 suoxiao four_corner_coordinate_positions[0][0] += max; four_corner_coordinate_positions[0][1] += max; //變化1點(diǎn)的Y軸 four_corner_coordinate_positions[1][1] += max; //變化2點(diǎn)的X軸 four_corner_coordinate_positions[2][0] += max; } else if (offsetX < 0 && offsetY > 0) { //變化0點(diǎn)的位置 kuoda four_corner_coordinate_positions[0][0] -= max; four_corner_coordinate_positions[0][1] -= max; //變化1點(diǎn)的Y軸 four_corner_coordinate_positions[1][1] -= max; //變化2點(diǎn)的X軸 four_corner_coordinate_positions[2][0] -= max; } else if (offsetX < 0 && offsetY < 0) { //變化0點(diǎn)的位置 kuoda four_corner_coordinate_positions[0][0] -= max; four_corner_coordinate_positions[0][1] -= max; //變化1點(diǎn)的Y軸 four_corner_coordinate_positions[1][1] -= max; //變化2點(diǎn)的X軸 four_corner_coordinate_positions[2][0] -= max; } else if (offsetX > 0 && offsetY > 0) { //變化0點(diǎn)的位置 suoxiao four_corner_coordinate_positions[0][0] += max; four_corner_coordinate_positions[0][1] += max; //變化1點(diǎn)的Y軸 four_corner_coordinate_positions[1][1] += max; //變化2點(diǎn)的X軸 four_corner_coordinate_positions[2][0] += max; } break; case 1: if (offsetX > 0 && offsetY < 0) { //變化1點(diǎn)的位置 four_corner_coordinate_positions[1][0] += max; four_corner_coordinate_positions[1][1] -= max; //變化0點(diǎn)的Y軸 four_corner_coordinate_positions[0][1] -= max; //變化3點(diǎn)的X軸 four_corner_coordinate_positions[3][0] += max; } else if (offsetX < 0 && offsetY > 0) { //變化1點(diǎn)的位置 four_corner_coordinate_positions[1][0] -= max; four_corner_coordinate_positions[1][1] += max; //變化0點(diǎn)的Y軸 four_corner_coordinate_positions[0][1] += max; //變化3點(diǎn)的X軸 four_corner_coordinate_positions[3][0] -= max; } else if (offsetX < 0 && offsetY < 0) { //變化1點(diǎn)的位置 four_corner_coordinate_positions[1][0] -= max; four_corner_coordinate_positions[1][1] += max; //變化0點(diǎn)的Y軸 four_corner_coordinate_positions[0][1] += max; //變化3點(diǎn)的X軸 four_corner_coordinate_positions[3][0] -= max; } else if (offsetX > 0 && offsetY > 0) { //變化1點(diǎn)的位置 four_corner_coordinate_positions[1][0] += max; four_corner_coordinate_positions[1][1] -= max; //變化0點(diǎn)的Y軸 four_corner_coordinate_positions[0][1] -= max; //變化3點(diǎn)的X軸 four_corner_coordinate_positions[3][0] += max; } break; case 2: if (offsetX > 0 && offsetY < 0) { //變化2點(diǎn)的位置 suoxiao four_corner_coordinate_positions[2][0] += max; four_corner_coordinate_positions[2][1] -= max; //變化0點(diǎn)的X軸 four_corner_coordinate_positions[0][0] += max; //變化3點(diǎn)的Y軸 four_corner_coordinate_positions[3][1] -= max; } else if (offsetX < 0 && offsetY > 0) { //變化2點(diǎn)的位置 kuoda four_corner_coordinate_positions[2][0] -= max; four_corner_coordinate_positions[2][1] += max; //變化0點(diǎn)的X軸 four_corner_coordinate_positions[0][0] -= max; //變化3點(diǎn)的Y軸 four_corner_coordinate_positions[3][1] += max; } else if (offsetX < 0 && offsetY < 0) { //變化2點(diǎn)的位置 kuoda four_corner_coordinate_positions[2][0] -= max; four_corner_coordinate_positions[2][1] += max; //變化0點(diǎn)的X軸 four_corner_coordinate_positions[0][0] -= max; //變化3點(diǎn)的Y軸 four_corner_coordinate_positions[3][1] += max; } else if (offsetX > 0 && offsetY > 0) { //變化2點(diǎn)的位置 suoxiao four_corner_coordinate_positions[2][0] += max; four_corner_coordinate_positions[2][1] -= max; //變化0點(diǎn)的X軸 four_corner_coordinate_positions[0][0] += max; //變化3點(diǎn)的Y軸 four_corner_coordinate_positions[3][1] -= max; } break; case 3: if (offsetX > 0 && offsetY < 0) { //變化3點(diǎn)的位置 kuoda four_corner_coordinate_positions[3][0] += max; four_corner_coordinate_positions[3][1] += max; //變化1點(diǎn)的X軸 four_corner_coordinate_positions[1][0] += max; //變化2點(diǎn)的Y軸 four_corner_coordinate_positions[2][1] += max; } else if (offsetX < 0 && offsetY > 0) { //變化3點(diǎn)的位置 suoxiao four_corner_coordinate_positions[3][0] -= max; four_corner_coordinate_positions[3][1] -= max; //變化1點(diǎn)的X軸 four_corner_coordinate_positions[1][0] -= max; //變化2點(diǎn)的Y軸 four_corner_coordinate_positions[2][1] -= max; } else if (offsetX < 0 && offsetY < 0) { //變化3點(diǎn)的位置 suoxiao four_corner_coordinate_positions[3][0] -= max; four_corner_coordinate_positions[3][1] -= max; //變化1點(diǎn)的X軸 four_corner_coordinate_positions[1][0] -= max; //變化2點(diǎn)的Y軸 four_corner_coordinate_positions[2][1] -= max; } else if (offsetX > 0 && offsetY > 0) { //變化3點(diǎn)的位置 kuoda four_corner_coordinate_positions[3][0] += max; four_corner_coordinate_positions[3][1] += max; //變化1點(diǎn)的X軸 four_corner_coordinate_positions[1][0] += max; //變化2點(diǎn)的Y軸 four_corner_coordinate_positions[2][1] += max; } break; } } /** * 判斷按下的點(diǎn)在圓圈內(nèi) * * @param x 按下的X坐標(biāo) * @param y 按下的Y坐標(biāo) * @return 返回按到的是哪個(gè)點(diǎn), 沒有則返回-1 * 點(diǎn)陣示意: * 0 1 * 2 3 */ private int isInTheCornerCircle(float x, float y) { for (int i = 0; i < four_corner_coordinate_positions.length; i++) { float a = four_corner_coordinate_positions[i][0]; float b = four_corner_coordinate_positions[i][1]; float temp1 = (float) Math.pow((x - a), 2); float temp2 = (float) Math.pow((y - b), 2); if (((float) RECT_CORNER_HEIGHT) >= Math.sqrt(temp1 + temp2)) { return i; } } return -1; } public interface onImageDetailsSizeChangged { void onBorderSizeChangged(int x, int y, int length); } public onImageDetailsSizeChangged onImageDetailsSizeChanggedl; public void setonImageDetailsSizeChangged(onImageDetailsSizeChangged onImageDetailsSizeChangged) { this.onImageDetailsSizeChanggedl = onImageDetailsSizeChangged; } }
以上所述是小編給大家介紹的Android自定義View實(shí)現(xiàn)照片裁剪框與照片裁剪功能,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- Android實(shí)現(xiàn)拍照、選擇圖片并裁剪圖片功能
- Android裁剪圖片為圓形圖片的實(shí)現(xiàn)原理與代碼
- 解決Android從相冊(cè)中獲取圖片出錯(cuò)圖片卻無法裁剪問題的方法
- Android實(shí)現(xiàn)從本地圖庫/相機(jī)拍照后裁剪圖片并設(shè)置頭像
- Android 7.0中拍照和圖片裁剪適配的問題詳解
- Android實(shí)現(xiàn)拍照及圖片裁剪(6.0以上權(quán)限處理及7.0以上文件管理)
- Android編程實(shí)現(xiàn)調(diào)用系統(tǒng)圖庫與裁剪圖片功能
- Android拍照或從圖庫選擇圖片并裁剪
- Android圖片裁剪功能實(shí)現(xiàn)代碼
- android實(shí)現(xiàn)拖拽裁剪功能
相關(guān)文章
詳解Android Studio3.5及使用AndroidX的一些坑
這篇文章主要介紹了詳解Android Studio3.5及使用AndroidX的一些坑,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11Android解析json數(shù)據(jù)示例代碼(三種方式)
本篇文章主要介紹了Android解析json數(shù)據(jù)示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03Android基于CountDownTimer實(shí)現(xiàn)倒計(jì)時(shí)功能
這篇文章主要介紹了Android基于CountDownTimer實(shí)現(xiàn)倒計(jì)時(shí)功能,簡(jiǎn)單分析了基于CountDownTimer類實(shí)現(xiàn)倒計(jì)時(shí)功能的技巧,需要的朋友可以參考下2015-12-12Android仿淘寶頭條向上滾動(dòng)廣告條ViewFlipper
這篇文章主要為大家詳細(xì)介紹了Android仿淘寶頭條向上滾動(dòng)廣告條ViewFlipper,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05Android App開發(fā)中使用RecyclerView替代ListView的實(shí)踐
RecyclerView是Android L即5.0版本以來新加入的一個(gè)組件,主要用來實(shí)現(xiàn)item的瀑布式排列,因而被人們廣泛認(rèn)為用來替代ListView,這里我們就來看一下Android App開發(fā)中使用RecyclerView替代ListView的實(shí)踐:2016-06-06Android Handler內(nèi)存泄漏詳解及其解決方案
在android開發(fā)過程中,我們可能會(huì)遇到過令人奔潰的OOM異常,這篇文章主要介紹了Android Handler內(nèi)存泄漏詳解及其解決方案,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08ViewModel中StateFlow和SharedFlow單元測(cè)試使用詳解
這篇文章主要為大家介紹了ViewModel中StateFlow和SharedFlow單元測(cè)試使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01解析Android開發(fā)優(yōu)化之:對(duì)界面UI的優(yōu)化詳解(三)
本篇文章主要討論一下復(fù)雜界面中常用的一種技術(shù)——界面延遲加載技術(shù)2013-05-05Android項(xiàng)目實(shí)戰(zhàn)之仿網(wǎng)易頂部導(dǎo)航欄效果
這篇文章主要為大家詳細(xì)介紹了Android項(xiàng)目實(shí)戰(zhàn)之仿網(wǎng)易頂部導(dǎo)航欄效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05