diff --git a/gallery/src/main/java/cc/winboll/studio/gallery/CropActivity.java b/gallery/src/main/java/cc/winboll/studio/gallery/CropActivity.java
index 0027525..f1eef7c 100644
--- a/gallery/src/main/java/cc/winboll/studio/gallery/CropActivity.java
+++ b/gallery/src/main/java/cc/winboll/studio/gallery/CropActivity.java
@@ -7,7 +7,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
-import android.widget.FrameLayout;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import cc.winboll.studio.libappbase.LogUtils;
@@ -23,7 +22,6 @@ public class CropActivity extends AppCompatActivity {
public static final String EXTRA_CROP_HEIGHT = "crop_height";
private CropCanvasView cropCanvasView;
- private CropOverlayView cropOverlay;
private Bitmap originalBitmap;
private String imagePath;
private String albumPath;
@@ -65,7 +63,6 @@ public class CropActivity extends AppCompatActivity {
});
cropCanvasView = findViewById(R.id.crop_canvas_view);
- cropOverlay = findViewById(R.id.crop_overlay);
loadImage();
}
@@ -85,7 +82,7 @@ public class CropActivity extends AppCompatActivity {
cropCanvasView.post(new Runnable() {
@Override
public void run() {
- initCropOverlay();
+ initCrop();
}
});
} else {
@@ -99,14 +96,14 @@ public class CropActivity extends AppCompatActivity {
}
}
- private void initCropOverlay() {
+ private void initCrop() {
cropCanvasView.initCanvas(originalBitmap.getWidth(), originalBitmap.getHeight(), cropRatio);
- int canvasW = cropCanvasView.getCanvasWidth();
- int canvasH = cropCanvasView.getCanvasHeight();
-
- cropOverlay.setTargetRatio(cropRatio);
- cropOverlay.initCanvas(canvasW, canvasH);
+ int viewW = cropCanvasView.getWidth();
+ int viewH = cropCanvasView.getHeight();
+ if (viewW > 0 && viewH > 0) {
+ cropCanvasView.scaleToView(viewW, viewH);
+ }
}
private void saveCroppedCover() {
@@ -116,7 +113,7 @@ public class CropActivity extends AppCompatActivity {
}
try {
- RectF cropRect = cropOverlay.getCropRect();
+ RectF cropRect = cropCanvasView.getCropRect();
RectF canvasBounds = cropCanvasView.getCanvasBounds();
RectF imageBounds = cropCanvasView.getImageBounds();
diff --git a/gallery/src/main/java/cc/winboll/studio/gallery/CropCanvasView.java b/gallery/src/main/java/cc/winboll/studio/gallery/CropCanvasView.java
index 7f44b65..7cfb626 100644
--- a/gallery/src/main/java/cc/winboll/studio/gallery/CropCanvasView.java
+++ b/gallery/src/main/java/cc/winboll/studio/gallery/CropCanvasView.java
@@ -7,10 +7,23 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
public class CropCanvasView extends View {
private Paint imagePaint;
+ private Paint borderPaint;
+ private Paint cornerPaint;
+ private RectF cropRect;
+ private int touchArea = 50;
+
+ private float lastX, lastY;
+ private int activeCorner = -1;
+ private static final int CORNER_TOP_LEFT = 0;
+ private static final int CORNER_TOP_RIGHT = 1;
+ private static final int CORNER_BOTTOM_LEFT = 2;
+ private static final int CORNER_BOTTOM_RIGHT = 3;
+ private static final int CORNER_CENTER = 4;
private int imageWidth;
private int imageHeight;
@@ -20,10 +33,12 @@ public class CropCanvasView extends View {
private int extendWidth;
private int canvasWidth;
private int canvasHeight;
+ private float minSize = 50;
private RectF imageBounds = new RectF();
private RectF canvasBounds = new RectF();
private Bitmap originalBitmap;
+ private float initialSpan;
public CropCanvasView(Context context) {
super(context);
@@ -43,6 +58,15 @@ public class CropCanvasView extends View {
private void init() {
imagePaint = new Paint();
imagePaint.setFilterBitmap(true);
+
+ borderPaint = new Paint();
+ borderPaint.setColor(Color.parseColor("#CCAA00"));
+ borderPaint.setStyle(Paint.Style.STROKE);
+ borderPaint.setStrokeWidth(3);
+
+ cornerPaint = new Paint();
+ cornerPaint.setColor(Color.WHITE);
+ cornerPaint.setStyle(Paint.Style.FILL);
}
public void setImageBitmap(Bitmap bitmap) {
@@ -72,6 +96,8 @@ public class CropCanvasView extends View {
imageBounds.set(left, top, left + imageWidth, top + imageHeight);
canvasBounds.set(0, 0, canvasWidth, canvasHeight);
+ cropRect = new RectF(0, 0, canvasWidth, canvasHeight);
+
requestLayout();
invalidate();
}
@@ -79,6 +105,8 @@ public class CropCanvasView extends View {
public void scaleToView(int viewWidth, int viewHeight) {
if (viewWidth > 0 && viewHeight > 0 && canvasWidth > 0 && canvasHeight > 0) {
float scale = Math.max((float) viewWidth / canvasWidth, (float) viewHeight / canvasHeight);
+ int oldCanvasW = canvasWidth;
+ int oldCanvasH = canvasHeight;
canvasWidth = (int) (canvasWidth * scale);
canvasHeight = (int) (canvasHeight * scale);
@@ -87,11 +115,24 @@ public class CropCanvasView extends View {
imageBounds.set(left, top, left + imageWidth, top + imageHeight);
canvasBounds.set(0, 0, canvasWidth, canvasHeight);
+ if (cropRect != null) {
+ float scaleX = (float) canvasWidth / oldCanvasW;
+ float scaleY = (float) canvasHeight / oldCanvasH;
+ cropRect.left *= scaleX;
+ cropRect.top *= scaleY;
+ cropRect.right *= scaleX;
+ cropRect.bottom *= scaleY;
+ }
+
requestLayout();
invalidate();
}
}
+ public RectF getCropRect() {
+ return new RectF(cropRect);
+ }
+
public int getCanvasWidth() {
return canvasWidth;
}
@@ -136,5 +177,165 @@ public class CropCanvasView extends View {
if (originalBitmap != null && !originalBitmap.isRecycled()) {
canvas.drawBitmap(originalBitmap, imageBounds.left, imageBounds.top, imagePaint);
}
+
+ if (cropRect != null) {
+ canvas.drawRect(cropRect, borderPaint);
+
+ canvas.drawCircle(cropRect.left, cropRect.top, 12, cornerPaint);
+ canvas.drawCircle(cropRect.right, cropRect.top, 12, cornerPaint);
+ canvas.drawCircle(cropRect.left, cropRect.bottom, 12, cornerPaint);
+ canvas.drawCircle(cropRect.right, cropRect.bottom, 12, cornerPaint);
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (cropRect == null || canvasBounds.isEmpty()) return super.onTouchEvent(event);
+
+ if (event.getPointerCount() == 2) {
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_POINTER_DOWN) {
+ initialSpan = getSpan(event);
+ return true;
+ } else if (action == MotionEvent.ACTION_MOVE) {
+ float span = getSpan(event);
+ if (initialSpan > 0) {
+ float scale = span / initialSpan;
+ float centerX = cropRect.centerX();
+ float centerY = cropRect.centerY();
+ float newWidth = cropRect.width() * scale;
+ float newHeight = newWidth / coverRatio;
+
+ newWidth = Math.max(minSize, Math.min(newWidth, canvasBounds.width()));
+ newHeight = newWidth / coverRatio;
+
+ cropRect.set(centerX - newWidth / 2, centerY - newHeight / 2,
+ centerX + newWidth / 2, centerY + newHeight / 2);
+
+ initialSpan = span;
+ invalidate();
+ }
+ return true;
+ }
+ }
+
+ float x = event.getX();
+ float y = event.getY();
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ lastX = x;
+ lastY = y;
+ activeCorner = getActiveCorner(x, y);
+ return true;
+
+ case MotionEvent.ACTION_MOVE:
+ float dx = x - lastX;
+ float dy = y - lastY;
+
+ if (activeCorner == CORNER_CENTER) {
+ float newLeft = cropRect.left + dx;
+ float newTop = cropRect.top + dy;
+ float newRight = cropRect.right + dx;
+ float newBottom = cropRect.bottom + dy;
+
+ if (newLeft >= canvasBounds.left && newRight <= canvasBounds.right) {
+ cropRect.left = newLeft;
+ cropRect.right = newRight;
+ }
+ if (newTop >= canvasBounds.top && newBottom <= canvasBounds.bottom) {
+ cropRect.top = newTop;
+ cropRect.bottom = newBottom;
+ }
+ } else if (activeCorner == CORNER_TOP_LEFT) {
+ adjustCorner(cropRect.left + dx, cropRect.top + dy, true, true);
+ } else if (activeCorner == CORNER_TOP_RIGHT) {
+ adjustCorner(cropRect.right + dx, cropRect.top + dy, false, true);
+ } else if (activeCorner == CORNER_BOTTOM_LEFT) {
+ adjustCorner(cropRect.left + dx, cropRect.bottom + dy, true, false);
+ } else if (activeCorner == CORNER_BOTTOM_RIGHT) {
+ adjustCorner(cropRect.right + dx, cropRect.bottom + dy, false, false);
+ }
+
+ lastX = x;
+ lastY = y;
+ invalidate();
+ return true;
+
+ case MotionEvent.ACTION_UP:
+ activeCorner = -1;
+ return true;
+ }
+ return super.onTouchEvent(event);
+ }
+
+ private void adjustCorner(float nx, float ny, boolean left, boolean top) {
+ float newWidth;
+ float newLeft = cropRect.left;
+ float newTop = cropRect.top;
+ float newRight = cropRect.right;
+ float newBottom = cropRect.bottom;
+
+ if (left) {
+ newWidth = cropRect.width() - (nx - cropRect.left);
+ newLeft = Math.max(canvasBounds.left, Math.min(nx, cropRect.right - minSize));
+ } else {
+ newWidth = nx - cropRect.left;
+ newRight = Math.min(canvasBounds.right, Math.max(nx, cropRect.left + minSize));
+ newLeft = cropRect.left;
+ }
+
+ float newHeight = newWidth / coverRatio;
+
+ if (top) {
+ newTop = Math.max(canvasBounds.top, Math.min(cropRect.bottom - minSize, cropRect.bottom - newHeight));
+ newBottom = newTop + newHeight;
+ } else {
+ newBottom = Math.min(canvasBounds.bottom, Math.max(cropRect.top + minSize, cropRect.top + newHeight));
+ newTop = newBottom - newHeight;
+ }
+
+ if (left) {
+ cropRect.left = newLeft;
+ cropRect.right = newLeft + newWidth;
+ } else {
+ cropRect.right = newRight;
+ cropRect.left = newRight - newWidth;
+ }
+
+ if (top) {
+ cropRect.top = newTop;
+ cropRect.bottom = newTop + newHeight;
+ } else {
+ cropRect.bottom = newBottom;
+ cropRect.top = newBottom - newHeight;
+ }
+ }
+
+ private int getActiveCorner(float x, float y) {
+ if (Math.abs(x - cropRect.left) <= touchArea && Math.abs(y - cropRect.top) <= touchArea) {
+ return CORNER_TOP_LEFT;
+ }
+ if (Math.abs(x - cropRect.right) <= touchArea && Math.abs(y - cropRect.top) <= touchArea) {
+ return CORNER_TOP_RIGHT;
+ }
+ if (Math.abs(x - cropRect.left) <= touchArea && Math.abs(y - cropRect.bottom) <= touchArea) {
+ return CORNER_BOTTOM_LEFT;
+ }
+ if (Math.abs(x - cropRect.right) <= touchArea && Math.abs(y - cropRect.bottom) <= touchArea) {
+ return CORNER_BOTTOM_RIGHT;
+ }
+ if (cropRect.contains(x, y)) {
+ return CORNER_CENTER;
+ }
+ return -1;
+ }
+
+ private float getSpan(MotionEvent event) {
+ float x0 = event.getX(0);
+ float y0 = event.getY(0);
+ float x1 = event.getX(1);
+ float y1 = event.getY(1);
+ return (float) Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
}
}
\ No newline at end of file
diff --git a/gallery/src/main/res/layout/activity_crop.xml b/gallery/src/main/res/layout/activity_crop.xml
index 73e87c3..45a5925 100644
--- a/gallery/src/main/res/layout/activity_crop.xml
+++ b/gallery/src/main/res/layout/activity_crop.xml
@@ -41,13 +41,8 @@
-
-
\ No newline at end of file