大部分的软件,

但凡包含登录注册的,

基本都会有选择头像功能,

而其中做的比较有逼格的,

一般会有一个选择框可以裁剪照片。

本文所需要实现的就是这样一种有逼格的效果:

右上角加了个图片框,按下确定可以裁剪正方形区域里的图片并显示在右上角。

实现思路:

1:首先需要自定义一个ZoomImageView来显示我们需要的图片,这个View需要让图片能够以合适的位置展现在当前布局的图片展示区域内(合适的位置值的是:如果图片长度大于屏幕,则压缩图片长度至屏幕宽度,高度等比压缩并居中显示,如果图片高度大于屏幕,则压缩图片高度至屏幕高度,长度等比压缩并居中显示。);

2:然后需要实现这个拖动的框框,该框框实现的功能有四点:拖动、扩大缩小、触摸时显示基准线、截图。

首先是布局设计image_details.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="55dp"android:background="#323441"><ImageButtonandroid: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"/><TextViewandroid: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"/><!--        <ImageButtonandroid: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"/>--><ImageViewandroid:id="@+id/testimg"android:layout_alignParentRight="true"android:layout_marginRight="10dp"android:layout_width="55dp"android:layout_height="55dp"/></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"><com.whale.nangua.pubuliuzhaopianqiang.ZoomImageViewandroid:id="@+id/zoom_image_view"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#303030"/><com.whale.nangua.pubuliuzhaopianqiang.ChoiceBorderViewandroid:id="@+id/zoom_choiceborder_view"android:layout_width="match_parent"android:layout_height="match_parent"/><Buttonandroid: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>

布局比较简单,两个View互相层叠。

自定义图片大小控制视图:ZoomImageView.java

代码注释很详细就不解释了。

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 {/*** 初始化状态常量*/public static final int STATUS_INIT = 1;/*** 用于对图片进行移动和缩放变换的矩阵*/private Matrix matrix = new Matrix();/*** 待展示的Bitmap对象*/private Bitmap sourceBitmap;/*** 记录当前操作的状态,可选值为STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE*/private int currentStatus;/*** ZoomImageView控件的宽度*/private int width;/*** ZoomImageView控件的高度*/private int height;/*** ZoomImageView构造函数,将当前操作状态设为STATUS_INIT。** @param context* @param attrs*/public ZoomImageView(Context context, AttributeSet attrs) {super(context, attrs);currentStatus = STATUS_INIT;}/*** 将待展示的图片设置进来。** @param bitmap 待展示的Bitmap对象*/public void setImageBitmap(Bitmap bitmap) {sourceBitmap = bitmap;invalidate();}@Overrideprotected 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();}}/*** 根据currentStatus的值来决定对图片进行什么样的绘制操作。*/@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);initBitmap(canvas);canvas.drawBitmap(sourceBitmap, matrix, null);}float translateY;//Y轴偏移量float translateX;//X轴偏移量/*** @param canvas* @autohr nangua* 对图片进行初始化操作,包括让图片居中,以及当图片大于屏幕宽高时对图片进行压缩。* <p>* 1.当图片宽度大于显示宽度、图片高度小于显示宽度:* 设置图片宽度为显示宽度,高度缩放*(图片宽度/显示宽度)* <p>* 2.当图片宽度小于显示宽度、图片高度大于显示宽度:* 设置图片高度为显示高度,宽度缩放*(图片高度/显示高 度)* <p>* 3.当图片宽度大于显示宽度,图片高度大于显示宽度:* 选取差度更大的一边进行压缩,另一边等比缩放* <p>* 4.当图片宽度小于显示宽度,图片高度小于显示宽度:* 选取差度更大的一边进行压缩,另一边等比缩放*/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;//找出差值大的一边,进行缩小if (distanceX >= distanceY) {ratio = width / (bitmapWidth * 1.0f);matrix.postScale(ratio, ratio);//此时横轴铺满,只需要对竖轴进行平移translateY = (height - sourceBitmap.getHeight() * ratio) / 2f;matrix.postTranslate(0, translateY);} else {ratio = height / (bitmapHeight * 1.0f);matrix.postScale(ratio, ratio);//此时竖轴铺满,只需要对横轴进行平移translateX = (width - sourceBitmap.getWidth() * ratio) / 2f;matrix.postTranslate(translateX, 0);    //在横纵轴上进行平移}//当图片宽度大于显示宽度、图片高度小于显示宽度:} else if (bitmapWidth > width) {// 当图片宽度大于屏幕宽度时,将图片等比例压缩,使它可以完全显示出来float ratio = width / (bitmapWidth * 1.0f); //压缩比例matrix.postScale(ratio, ratio);translateY = (height - (bitmapHeight * ratio)) / 2f;// 在纵坐标方向上进行偏移,以保证图片居中显示matrix.postTranslate(0, translateY);//当图片宽度小于显示宽度、图片高度大于显示宽度:} else if (bitmapHeight > height) {// 当图片高度大于屏幕高度时,将图片等比例压缩,使它可以完全显示出来float ratio = height / (bitmapHeight * 1.0f);   //压缩比例matrix.postScale(ratio, ratio);translateX = (width - (bitmapWidth * ratio)) / 2f;// 在横坐标方向上进行偏移,以保证图片居中显示matrix.postTranslate(translateX, 0);}} else {// 当图片的宽高都小于屏幕宽高时,选择差度小的一边铺满,另一边等比扩大//计算长和宽的差值int distanceX = Math.abs(width - bitmapWidth);int distanceY = Math.abs(height - bitmapHeight);float ratio;//找出差值小的一边,进行扩大if (distanceX <= distanceY) {ratio = width / (bitmapWidth * 1.0f);matrix.postScale(ratio, ratio);//此时横轴铺满,只需要对竖轴进行平移translateY = (height - sourceBitmap.getHeight() * ratio) / 2f;matrix.postTranslate(0, translateY);} else {ratio = height / (bitmapHeight * 1.0f);matrix.postScale(ratio, ratio);//此时竖轴铺满,只需要对横轴进行平移translateX = (width - sourceBitmap.getWidth() * ratio) / 2f;matrix.postTranslate(translateX, 0);    //在横纵轴上进行平移}}//进行绘制canvas.drawBitmap(sourceBitmap, matrix, null);}}}

重点来了,相册选取框视图: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;/*** 相册选择框的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; //边框长度private int RECT_BORDER_WITH = 3 * scale; //长方形框框粗private int RECT_CORNER_WITH = 6 * scale; //四个角的粗private int RECT_CORNER_HEIGHT = 20 * scale; //四个角的长度//四个点坐标private static float[][] four_corner_coordinate_positions;private static int NOW_MOVE_STATE = 1; //移动状态,默认为1,Y轴=1,X轴=2private static boolean MOVE_OR_ZOOM_STATE = true; //移动或缩放状态, true 为移动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*/@Overrideprotected 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();//初始化四个点的坐标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;  //长方形的粗半距private int temp2 = (RECT_CORNER_WITH + RECT_BORDER_WITH) / 2;  //四个角的粗半距/*** RECT_CORNER_WITH = 6* RECT_BORDER_WITH  =3** @param canvas*/@Overrideprotected 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); //设置空心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);//画四个角的画笔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);//共四根线//竖1canvas.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);//竖2canvas.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);//横1canvas.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);//横2canvas.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;// 用户按下的点private int POINT_STATE = -1; //判断用户是缩小还是放大 0放大 1缩小@Overridepublic 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; //设置false为缩放状态point = isInTheCornerCircle(event.getX(), event.getY());}lastX = x;lastY = y;invalidate();break;case MotionEvent.ACTION_MOVE:offsetX = x - lastX;offsetY = y - lastY;//判断当前是扩大还是缩小操作judgementXandY();//限定移动范围//移动状态:只有在移动状态下才能移动if (MOVE_OR_ZOOM_STATE) {getoffsetXandoffsetY();//四个点的坐标信息也要随之改变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;//更新回调接口onImageDetailsSizeChanggedl.onBorderSizeChangged((int) four_corner_coordinate_positions[0][0],(int) four_corner_coordinate_positions[0][1],(int) borderLength);invalidate();}// this.scrollBy(-offsetX, -offsetY);   //这里弃用,后面改用了四点坐标移动代替背景移动}//在缩放状态下else {//按住某一个点,该点的坐标改变,其他2个点坐标跟着改变,对点坐标不变max = Math.abs(offsetX) >= Math.abs(offsetY) ? Math.abs(offsetX) : Math.abs(offsetY);//只有在扩大操作才进行边界范围判断if (POINT_STATE == 0) {getoffsetXandoffsetY(); //边界范围判断}//缩小操作时进行边界不能太小判断else if (POINT_STATE == 1) {//如果边长+max太小,直接返回if (borderLength - max <= RECT_CORNER_HEIGHT*2-temp2) {max = 0;}}//改变坐标changgeFourCoodinatePosition(point, offsetX, offsetY);//更新边长notifyNowborderLength();//更新回调接口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; //回归为默认的移动状态invalidate();break;}return true;}/*** 更新矩形框边长的方法*/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;//扩大} 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() {//如果是移动状态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;}}//如果是缩放状态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;/*** 扩大缩放方法* 根据用户传来的点改变其他点的坐标* 按住某一个点,该点的坐标改变,其他2个点坐标跟着改变,对点坐标不变* 点阵示意:* 0   1* 2   3** @param point   用户按的点* @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点的位置   suoxiaofour_corner_coordinate_positions[0][0] += max;four_corner_coordinate_positions[0][1] += max;//变化1点的Y轴four_corner_coordinate_positions[1][1] += max;//变化2点的X轴four_corner_coordinate_positions[2][0] += max;} else if (offsetX < 0 && offsetY > 0) {//变化0点的位置   kuodafour_corner_coordinate_positions[0][0] -= max;four_corner_coordinate_positions[0][1] -= max;//变化1点的Y轴four_corner_coordinate_positions[1][1] -= max;//变化2点的X轴four_corner_coordinate_positions[2][0] -= max;} else if (offsetX < 0 && offsetY < 0) {//变化0点的位置   kuodafour_corner_coordinate_positions[0][0] -= max;four_corner_coordinate_positions[0][1] -= max;//变化1点的Y轴four_corner_coordinate_positions[1][1] -= max;//变化2点的X轴four_corner_coordinate_positions[2][0] -= max;} else if (offsetX > 0 && offsetY > 0) {//变化0点的位置   suoxiaofour_corner_coordinate_positions[0][0] += max;four_corner_coordinate_positions[0][1] += max;//变化1点的Y轴four_corner_coordinate_positions[1][1] += max;//变化2点的X轴four_corner_coordinate_positions[2][0] += max;}break;case 1:if (offsetX > 0 && offsetY < 0) {//变化1点的位置four_corner_coordinate_positions[1][0] += max;four_corner_coordinate_positions[1][1] -= max;//变化0点的Y轴four_corner_coordinate_positions[0][1] -= max;//变化3点的X轴four_corner_coordinate_positions[3][0] += max;} else if (offsetX < 0 && offsetY > 0) {//变化1点的位置four_corner_coordinate_positions[1][0] -= max;four_corner_coordinate_positions[1][1] += max;//变化0点的Y轴four_corner_coordinate_positions[0][1] += max;//变化3点的X轴four_corner_coordinate_positions[3][0] -= max;} else if (offsetX < 0 && offsetY < 0) {//变化1点的位置four_corner_coordinate_positions[1][0] -= max;four_corner_coordinate_positions[1][1] += max;//变化0点的Y轴four_corner_coordinate_positions[0][1] += max;//变化3点的X轴four_corner_coordinate_positions[3][0] -= max;} else if (offsetX > 0 && offsetY > 0) {//变化1点的位置four_corner_coordinate_positions[1][0] += max;four_corner_coordinate_positions[1][1] -= max;//变化0点的Y轴four_corner_coordinate_positions[0][1] -= max;//变化3点的X轴four_corner_coordinate_positions[3][0] += max;}break;case 2:if (offsetX > 0 && offsetY < 0) {//变化2点的位置   suoxiaofour_corner_coordinate_positions[2][0] += max;four_corner_coordinate_positions[2][1] -= max;//变化0点的X轴four_corner_coordinate_positions[0][0] += max;//变化3点的Y轴four_corner_coordinate_positions[3][1] -= max;} else if (offsetX < 0 && offsetY > 0) {//变化2点的位置   kuodafour_corner_coordinate_positions[2][0] -= max;four_corner_coordinate_positions[2][1] += max;//变化0点的X轴four_corner_coordinate_positions[0][0] -= max;//变化3点的Y轴four_corner_coordinate_positions[3][1] += max;} else if (offsetX < 0 && offsetY < 0) {//变化2点的位置   kuodafour_corner_coordinate_positions[2][0] -= max;four_corner_coordinate_positions[2][1] += max;//变化0点的X轴four_corner_coordinate_positions[0][0] -= max;//变化3点的Y轴four_corner_coordinate_positions[3][1] += max;} else if (offsetX > 0 && offsetY > 0) {//变化2点的位置   suoxiaofour_corner_coordinate_positions[2][0] += max;four_corner_coordinate_positions[2][1] -= max;//变化0点的X轴four_corner_coordinate_positions[0][0] += max;//变化3点的Y轴four_corner_coordinate_positions[3][1] -= max;}break;case 3:if (offsetX > 0 && offsetY < 0) {//变化3点的位置   kuodafour_corner_coordinate_positions[3][0] += max;four_corner_coordinate_positions[3][1] += max;//变化1点的X轴four_corner_coordinate_positions[1][0] += max;//变化2点的Y轴four_corner_coordinate_positions[2][1] += max;} else if (offsetX < 0 && offsetY > 0) {//变化3点的位置   suoxiaofour_corner_coordinate_positions[3][0] -= max;four_corner_coordinate_positions[3][1] -= max;//变化1点的X轴four_corner_coordinate_positions[1][0] -= max;//变化2点的Y轴four_corner_coordinate_positions[2][1] -= max;} else if (offsetX < 0 && offsetY < 0) {//变化3点的位置   suoxiaofour_corner_coordinate_positions[3][0] -= max;four_corner_coordinate_positions[3][1] -= max;//变化1点的X轴four_corner_coordinate_positions[1][0] -= max;//变化2点的Y轴four_corner_coordinate_positions[2][1] -= max;} else if (offsetX > 0 && offsetY > 0) {//变化3点的位置   kuodafour_corner_coordinate_positions[3][0] += max;four_corner_coordinate_positions[3][1] += max;//变化1点的X轴four_corner_coordinate_positions[1][0] += max;//变化2点的Y轴four_corner_coordinate_positions[2][1] += max;}break;}}/*** 判断按下的点在圆圈内** @param x 按下的X坐标* @param y 按下的Y坐标* @return 返回按到的是哪个点, 没有则返回-1* 点阵示意:* 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;}}

为了实现这个相框我写了557行,是的其中有大量写的很蠢很重复的代码,大可以花点时间进行优化(逃)。

实现的思路是这样的:首先要确定四个点的位置,然后根据这四个点的位置在onDraw方法中画出相框的边框,四个角框,再在onTouchListner中通过计算按下的坐标偏移量改变四个点的位置从而改变onDraw中整个相框视图的位置。

但是难点在于手势的判断以及不同情况下缩放与扩大的边界值溢出问题,这个问题大概搞了一下午。。。很烧脑

但是总的来说加强了对自定义视图的理解,发现了一些解决问题的新思路。

嗯,继续努力。

Android 自定义View实现照片裁剪框与照片裁剪相关推荐

  1. 精通Android自定义View(十一)绘制篇Canvas分析之裁剪

    clipRect(int left, int top, int right, int bottom)  这个方法作用就是裁切一个矩形出来,但是图形不还是在canvas上面的,所以本质上还是裁切的can ...

  2. 精通Android自定义View(十四)绘制水平向右加载的进度条

    1引言 1 精通Android自定义View(一)View的绘制流程简述 2 精通Android自定义View(二)View绘制三部曲 3 精通Android自定义View(三)View绘制三部曲综合 ...

  3. 精通Android自定义View(十二)绘制圆形进度条

    1 绘图基础简析 1 精通Android自定义View(一)View的绘制流程简述 2 精通Android自定义View(二)View绘制三部曲 3 精通Android自定义View(三)View绘制 ...

  4. [原] Android 自定义View 密码框 例子

    遵从准则 暴露您view中所有影响可见外观的属性或者行为. 通过XML添加和设置样式 通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 详细步骤见:Android 自定义View步骤 ...

  5. 【朝花夕拾】Android自定义View之(一)手把手教你看懂View绘制流程——向源码要答案

    前言 原文:Android自定义View之(一)手把手教你看懂View绘制流程--向源码要答案 View作为整个app的颜值担当,在Android体系中占有重要的地位.深入理解Android View ...

  6. android 立体 流量球,Android自定义View——实现水波纹效果类似剩余流量球

    Android自定义View--实现水波纹效果类似剩余流量球 三个点   pre   ber   block   span   初始化   move   理解最近突然手痒就想搞个贝塞尔曲线做个水波纹效 ...

  7. android 自定义view: 跑马灯-光圈

    本系列自定义View全部采用kt **系统: **mac android studio: 4.1.3 **kotlin version:**1.5.0 gradle: gradle-6.5-bin.z ...

  8. Android 自定义View 实例2_Clipping Canvas

    上一篇 Android 自定义View 实例_ 画图  参考: https://blog.csdn.net/whjk20/article/details/115639448 这里是Canvas 的裁剪 ...

  9. Android自定义View分享——仿微信朋友圈图片合并效果

    写在前面 笔者近来在学习Android自定义View,收集了一些不算复杂但又"长得"还可以的自定义View效果实现,之前分享过两个效果:一个水平的进度条,一个圆形温度显示器,如果你 ...

  10. Android自定义View之Paint绘制文字和线

    Android自定义View系列 Android自定义View注意事项 Android自定义View之图像的色彩处理 Android自定义View之Canvas Android自定义View之轻松实现 ...

最新文章

  1. div如何添加滚动条?
  2. Nature综述:微生物的社交网络 - 营养缺陷型如何塑造复杂群落
  3. 正确删除ORACLE归档日志文件
  4. 在Kotlin中 使用js 函数
  5. Steeltoe 2.4新增代码生成工具、全新入门指南等,助力.NET微服务开发
  6. HDOJ1166 敌兵布阵【线段树】
  7. bootstraptable导出excel独立使用_使用 EasyPOI 优雅导出Excel模板数据(含图片)
  8. 1022词法分析实验总结
  9. UML学习-----类图
  10. Reduce归约 证明原理
  11. Android中app的请求抓包工具 Fiddler 详解
  12. 5.1声道测试文件下载
  13. Spring Security 5
  14. java 中int常量池_Java基础2:基本数据类型与常量池
  15. android 环信集成demo,集成环信即时通讯(导入demo到AndroidStudio)
  16. ubuntu下安装三维渲染引擎OSG详解
  17. NXOPEN/UG二次开发C#---导入igs文件,获得导入的TaggedObject
  18. 不懂编程也可以开发网站
  19. win10 kms激活
  20. 自制电脑红外遥控接收器(PC软解码)

热门文章

  1. 基于单片机的超市储物柜设计_基于单片机的新型智能储物柜设计
  2. Android虚拟机的安装
  3. 安卓手机管理_七色米ERP(七色米ERP进销存管理)V1.2.1 安卓手机版
  4. 倾斜摄影静态单体化 BIM模型调用解决思路
  5. Android开发,app多种语言包
  6. git目录下object文件过大清理
  7. 透视宝移动端对Unity手机游戏引擎监控实现 1
  8. excel 删除重复项
  9. hdu--6045 Is Derek Lying
  10. java调用百度地图api,展示北京地铁路线