From d392ba09d28beb06972865a8e019999f9a8919a7 Mon Sep 17 00:00:00 2001 From: Issei Aoki Date: Wed, 16 Mar 2016 15:25:46 +0900 Subject: [PATCH 01/35] Update rotate algorithm and refactor --- .../simplecropview/CropImageView.java | 199 +++++++++--------- 1 file changed, 103 insertions(+), 96 deletions(-) diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java index be23f1b..fe8d34d 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java @@ -145,6 +145,7 @@ public Parcelable onSaveInstanceState() { ss.handleColor = this.mHandleColor; ss.guideColor = this.mGuideColor; ss.initialFrameScale = this.mInitialFrameScale; + ss.angle = this.mAngle; return ss; } @@ -170,41 +171,38 @@ public void onRestoreInstanceState(Parcelable state) { this.mHandleColor = ss.handleColor; this.mGuideColor = ss.guideColor; this.mInitialFrameScale = ss.initialFrameScale; + this.mAngle = ss.angle; setImageBitmap(ss.image); requestLayout(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - final int viewWidth = MeasureSpec.getSize(widthMeasureSpec); final int viewHeight = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(viewWidth, viewHeight); + + mViewWidth = viewWidth - getPaddingLeft() - getPaddingRight(); + mViewHeight = viewHeight - getPaddingTop() - getPaddingBottom(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - mViewWidth = r - l - getPaddingLeft() - getPaddingRight(); - mViewHeight = b - t - getPaddingTop() - getPaddingBottom(); if (getDrawable() != null) initLayout(mViewWidth, mViewHeight); } @Override public void onDraw(Canvas canvas) { - super.onDraw(canvas); + canvas.drawColor(mBackgroundColor); if (mIsInitialized) { setMatrix(); - Matrix localMatrix1 = new Matrix(); - localMatrix1.postConcat(this.mMatrix); Bitmap bm = getBitmap(); if (bm != null) { - canvas.drawBitmap(bm, localMatrix1, mPaintBitmap); + canvas.drawBitmap(bm, mMatrix, mPaintBitmap); // draw edit frame - drawEditFrame(canvas); + drawCropFrame(canvas); } } } @@ -227,7 +225,6 @@ private void handleStyleable(Context context, AttributeSet attrs, int defStyle, } } mBackgroundColor = ta.getColor(R.styleable.CropImageView_backgroundColor, TRANSPARENT); - super.setBackgroundColor(mBackgroundColor); mOverlayColor = ta.getColor(R.styleable.CropImageView_overlayColor, TRANSLUCENT_BLACK); mFrameColor = ta.getColor(R.styleable.CropImageView_frameColor, WHITE); mHandleColor = ta.getColor(R.styleable.CropImageView_handleColor, WHITE); @@ -271,67 +268,66 @@ private void handleStyleable(Context context, AttributeSet attrs, int defStyle, // Drawing method ////////////////////////////////////////////////////////////////////////////// - private void drawEditFrame(Canvas canvas) { + private void drawCropFrame(Canvas canvas) { if (!mIsCropEnabled) return; + drawOverlay(canvas); + drawFrame(canvas); + if (mShowGuide) drawGuidelines(canvas); + if (mShowHandle) drawHandles(canvas); + } - if (mCropMode == CropMode.CIRCLE) { - mPaintTransparent.setFilterBitmap(true); - mPaintTransparent.setColor(mOverlayColor); - mPaintTransparent.setStyle(Paint.Style.FILL); + private void drawHandles(Canvas canvas) { + mPaintFrame.setStyle(Paint.Style.FILL); + mPaintFrame.setColor(mHandleColor); + canvas.drawCircle(mFrameRect.left, mFrameRect.top, mHandleSize, mPaintFrame); + canvas.drawCircle(mFrameRect.right, mFrameRect.top, mHandleSize, mPaintFrame); + canvas.drawCircle(mFrameRect.left, mFrameRect.bottom, mHandleSize, mPaintFrame); + canvas.drawCircle(mFrameRect.right, mFrameRect.bottom, mHandleSize, mPaintFrame); + } - Path path = new Path(); - path.addRect(mImageRect.left, mImageRect.top, mImageRect.right, mImageRect.bottom, - Path.Direction.CW); - path.addCircle((mFrameRect.left + mFrameRect.right) / 2, - (mFrameRect.top + mFrameRect.bottom) / 2, - (mFrameRect.right - mFrameRect.left) / 2, Path.Direction.CCW); - canvas.drawPath(path, mPaintTransparent); + private void drawGuidelines(Canvas canvas) { + mPaintFrame.setColor(mGuideColor); + mPaintFrame.setStrokeWidth(mGuideStrokeWeight); + float h1 = mFrameRect.left + (mFrameRect.right - mFrameRect.left) / 3.0f; + float h2 = mFrameRect.right - (mFrameRect.right - mFrameRect.left) / 3.0f; + float v1 = mFrameRect.top + (mFrameRect.bottom - mFrameRect.top) / 3.0f; + float v2 = mFrameRect.bottom - (mFrameRect.bottom - mFrameRect.top) / 3.0f; - } else { - mPaintTransparent.setFilterBitmap(true); - mPaintTransparent.setColor(mOverlayColor); - mPaintTransparent.setStyle(Paint.Style.FILL); - - canvas.drawRect(mImageRect.left, mImageRect.top, mImageRect.right, mFrameRect.top, - mPaintTransparent); - canvas.drawRect(mImageRect.left, mFrameRect.bottom, mImageRect.right, mImageRect.bottom, - mPaintTransparent); - canvas.drawRect(mImageRect.left, mFrameRect.top, mFrameRect.left, mFrameRect.bottom, - mPaintTransparent); - canvas.drawRect(mFrameRect.right, mFrameRect.top, mImageRect.right, mFrameRect.bottom, - mPaintTransparent); - } + canvas.drawLine(h1, mFrameRect.top, h1, mFrameRect.bottom, mPaintFrame); + canvas.drawLine(h2, mFrameRect.top, h2, mFrameRect.bottom, mPaintFrame); + canvas.drawLine(mFrameRect.left, v1, mFrameRect.right, v1, mPaintFrame); + canvas.drawLine(mFrameRect.left, v2, mFrameRect.right, v2, mPaintFrame); + } + private void drawFrame(Canvas canvas) { mPaintFrame.setAntiAlias(true); mPaintFrame.setFilterBitmap(true); mPaintFrame.setStyle(Paint.Style.STROKE); mPaintFrame.setColor(mFrameColor); mPaintFrame.setStrokeWidth(mFrameStrokeWeight); - canvas.drawRect(mFrameRect.left, mFrameRect.top, mFrameRect.right, mFrameRect.bottom, - mPaintFrame); - - if (mShowGuide) { - mPaintFrame.setColor(mGuideColor); - mPaintFrame.setStrokeWidth(mGuideStrokeWeight); - float h1 = mFrameRect.left + (mFrameRect.right - mFrameRect.left) / 3.0f; - float h2 = mFrameRect.right - (mFrameRect.right - mFrameRect.left) / 3.0f; - float v1 = mFrameRect.top + (mFrameRect.bottom - mFrameRect.top) / 3.0f; - float v2 = mFrameRect.bottom - (mFrameRect.bottom - mFrameRect.top) / 3.0f; - - canvas.drawLine(h1, mFrameRect.top, h1, mFrameRect.bottom, mPaintFrame); - canvas.drawLine(h2, mFrameRect.top, h2, mFrameRect.bottom, mPaintFrame); - canvas.drawLine(mFrameRect.left, v1, mFrameRect.right, v1, mPaintFrame); - canvas.drawLine(mFrameRect.left, v2, mFrameRect.right, v2, mPaintFrame); - } + mPaintFrame); + } - if (mShowHandle) { - mPaintFrame.setStyle(Paint.Style.FILL); - mPaintFrame.setColor(mHandleColor); - canvas.drawCircle(mFrameRect.left, mFrameRect.top, mHandleSize, mPaintFrame); - canvas.drawCircle(mFrameRect.right, mFrameRect.top, mHandleSize, mPaintFrame); - canvas.drawCircle(mFrameRect.left, mFrameRect.bottom, mHandleSize, mPaintFrame); - canvas.drawCircle(mFrameRect.right, mFrameRect.bottom, mHandleSize, mPaintFrame); + private void drawOverlay(Canvas canvas) { + mPaintTransparent.setAntiAlias(true); + mPaintTransparent.setFilterBitmap(true); + mPaintTransparent.setColor(mOverlayColor); + mPaintTransparent.setStyle(Paint.Style.FILL); + + if (mCropMode == CropMode.CIRCLE) { + Path path = new Path(); + path.addRect(mImageRect.left, mImageRect.top, mImageRect.right, mImageRect.bottom, + Path.Direction.CW); + path.addCircle((mFrameRect.left + mFrameRect.right) / 2, + (mFrameRect.top + mFrameRect.bottom) / 2, + (mFrameRect.right - mFrameRect.left) / 2, Path.Direction.CCW); + canvas.drawPath(path, mPaintTransparent); + } else { + Path path = new Path(); + path.addRect(mImageRect.left, mImageRect.top, mImageRect.right, mImageRect.bottom, Path.Direction.CW); + path.addRect(mFrameRect.left, mFrameRect.top, mFrameRect.right, mFrameRect.bottom, Path.Direction.CCW); + canvas.drawPath(path, mPaintTransparent); } } @@ -352,12 +348,12 @@ private void initLayout(int viewW, int viewH) { float w = (float) viewW; float h = (float) viewH; float viewRatio = w / h; - float imgRatio = mImgWidth / mImgHeight; + float imgRatio = getRotatedWidth() / getRotatedHeight(); float scale = 1.0f; if (imgRatio >= viewRatio) { - scale = w / mImgWidth; + scale = w / getRotatedWidth(); } else if (imgRatio < viewRatio) { - scale = h / mImgHeight; + scale = h / getRotatedHeight(); } setCenter(new PointF(getPaddingLeft() + w * 0.5f, getPaddingTop() + h * 0.5f)); setScale(scale); @@ -385,8 +381,8 @@ private void initCropFrame() { float r = arrayOfFloat[6]; float b = arrayOfFloat[7]; - mFrameRect = new RectF(l, t, r, b); - mImageRect = new RectF(l, t, r, b); + mFrameRect = new RectF(Math.min(l, r), Math.min(t, b), Math.max(l, r), Math.max(t, b)); + mImageRect = new RectF(Math.min(l, r), Math.min(t, b), Math.max(l, r), Math.max(t, b)); } // Touch Event ///////////////////////////////////////////////////////////////////////////////// @@ -538,6 +534,15 @@ private boolean isInsideCornerRightBottom(float x, float y) { return sq(mHandleSize + mTouchPadding) >= d; } + private float getRotatedWidth(){ + return mAngle % 180 == 0 ? mImgWidth : mImgHeight; + } + + private float getRotatedHeight(){ + return mAngle % 180 == 0 ? mImgHeight : mImgWidth; + } + + // Adjust frame //////////////////////////////////////////////////////////////////////////////// private void moveFrame(float x, float y) { @@ -797,25 +802,23 @@ private boolean isHeightTooSmall() { private void adjustRatio() { if (mImageRect == null) return; - float imgW = mImageRect.right - mImageRect.left; - float imgH = mImageRect.bottom - mImageRect.top; - float frameW = getRatioX(imgW); - float frameH = getRatioY(imgH); - float imgRatio = imgW / imgH; + float frameW = getRatioX(mImageRect.width()); + float frameH = getRatioY(mImageRect.height()); + float imgRatio = mImageRect.width() / mImageRect.height(); float frameRatio = frameW / frameH; float l = mImageRect.left, t = mImageRect.top, r = mImageRect.right, b = mImageRect.bottom; if (frameRatio >= imgRatio) { l = mImageRect.left; r = mImageRect.right; float hy = (mImageRect.top + mImageRect.bottom) * 0.5f; - float hh = (imgW / frameRatio) * 0.5f; + float hh = (mImageRect.width() / frameRatio) * 0.5f; t = hy - hh; b = hy + hh; } else if (frameRatio < imgRatio) { t = mImageRect.top; b = mImageRect.bottom; float hx = (mImageRect.left + mImageRect.right) * 0.5f; - float hw = imgH * frameRatio * 0.5f; + float hw = mImageRect.height() * frameRatio * 0.5f; l = hx - hw; r = hx + hw; } @@ -832,7 +835,7 @@ private void adjustRatio() { private float getRatioX(float w) { switch (mCropMode) { case RATIO_FIT_IMAGE: - return mImgWidth; + return mImageRect.width(); case RATIO_FREE: return w; case RATIO_4_3: @@ -856,7 +859,7 @@ private float getRatioX(float w) { private float getRatioY(float h) { switch (mCropMode) { case RATIO_FIT_IMAGE: - return mImgHeight; + return mImageRect.height(); case RATIO_FREE: return h; case RATIO_4_3: @@ -880,7 +883,7 @@ private float getRatioY(float h) { private float getRatioX() { switch (mCropMode) { case RATIO_FIT_IMAGE: - return mImgWidth; + return mImageRect.width(); case RATIO_4_3: return 4.0f; case RATIO_3_4: @@ -902,7 +905,7 @@ private float getRatioX() { private float getRatioY() { switch (mCropMode) { case RATIO_FIT_IMAGE: - return mImgHeight; + return mImageRect.height(); case RATIO_4_3: return 3.0f; case RATIO_3_4: @@ -999,6 +1002,7 @@ public void setImageURI(Uri uri) { private void updateDrawableInfo() { Drawable d = getDrawable(); + mAngle = 0f; if (d != null) { initLayout(mViewWidth, mViewHeight); } @@ -1010,15 +1014,8 @@ private void updateDrawableInfo() { * @param degrees angle of ration in degrees. */ public void rotateImage(RotateDegrees degrees) { - Bitmap source = getBitmap(); - if (source == null) return; - - int angle = degrees.getValue(); - Matrix matrix = new Matrix(); - matrix.postRotate(angle); - Bitmap rotated = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), - matrix, true); - setImageBitmap(rotated); + mAngle = (mAngle + degrees.getValue()) % 360; + initLayout(mViewWidth, mViewHeight); } /** @@ -1030,6 +1027,10 @@ public Bitmap getCroppedBitmap() { Bitmap source = getBitmap(); if (source == null) return null; + Matrix rotateMatrix = new Matrix(); + rotateMatrix.setRotate(mAngle, source.getWidth() / 2, source.getHeight()/2); + Bitmap rotated = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), rotateMatrix, true); + int x, y, w, h; float l = (mFrameRect.left / mScale); float t = (mFrameRect.top / mScale); @@ -1040,14 +1041,14 @@ public Bitmap getCroppedBitmap() { w = Math.round(r - l); h = Math.round(b - t); - if (x + w > source.getWidth()) { - w = source.getWidth() - x; + if (x + w > rotated.getWidth()) { + w = rotated.getWidth() - x; } - if (y + h > source.getHeight()) { - h = source.getHeight() - y; + if (y + h > rotated.getHeight()) { + h = rotated.getHeight() - y; } - Bitmap cropped = Bitmap.createBitmap(source, x, y, w, h, null, false); + Bitmap cropped = Bitmap.createBitmap(rotated, x, y, w, h, null, false); if (mCropMode != CropMode.CIRCLE) return cropped; return getCircularBitmap(cropped); } @@ -1064,6 +1065,10 @@ public Bitmap getRectBitmap() { Bitmap source = getBitmap(); if (source == null) return null; + Matrix rotateMatrix = new Matrix(); + rotateMatrix.setRotate(mAngle, source.getWidth() / 2, source.getHeight()/2); + Bitmap rotated = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), rotateMatrix, true); + int x, y, w, h; float l = (mFrameRect.left / mScale); float t = (mFrameRect.top / mScale); @@ -1074,14 +1079,14 @@ public Bitmap getRectBitmap() { w = Math.round(r - l); h = Math.round(b - t); - if (x + w > source.getWidth()) { - w = source.getWidth() - x; + if (x + w > rotated.getWidth()) { + w = rotated.getWidth() - x; } - if (y + h > source.getHeight()) { - h = source.getHeight() - y; + if (y + h > rotated.getHeight()) { + h = rotated.getHeight() - y; } - return Bitmap.createBitmap(source, x, y, w, h, null, false); + return Bitmap.createBitmap(rotated, x, y, w, h, null, false); } /** @@ -1208,7 +1213,6 @@ public void setGuideColor(int guideColor) { */ public void setBackgroundColor(int bgColor) { this.mBackgroundColor = bgColor; - super.setBackgroundColor(this.mBackgroundColor); invalidate(); } @@ -1426,6 +1430,7 @@ public static class SavedState extends BaseSavedState { int handleColor; int guideColor; float initialFrameScale; + float angle; SavedState(Parcelable superState) { super(superState); @@ -1453,6 +1458,7 @@ private SavedState(Parcel in) { handleColor = in.readInt(); guideColor = in.readInt(); initialFrameScale = in.readFloat(); + angle = in.readFloat(); } @Override @@ -1478,6 +1484,7 @@ public void writeToParcel(Parcel out, int flag) { out.writeInt(handleColor); out.writeInt(guideColor); out.writeFloat(initialFrameScale); + out.writeFloat(angle); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { From f02805e524315129f303eae52439f52ffd71dfcb Mon Sep 17 00:00:00 2001 From: Issei Aoki Date: Thu, 17 Mar 2016 18:33:07 +0900 Subject: [PATCH 02/35] Add rotate animation(frame not show) --- .../simplecropviewsample/MainActivity.java | 2 +- .../simplecropview/CropImageView.java | 284 +++++++++++------- .../animation/SimpleValueAnimator.java | 8 + .../SimpleValueAnimatorListener.java | 7 + .../animation/ValueAnimatorV14.java | 83 +++++ .../animation/ValueAnimatorV8.java | 88 ++++++ 6 files changed, 365 insertions(+), 107 deletions(-) create mode 100644 simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimator.java create mode 100644 simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimatorListener.java create mode 100644 simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java create mode 100644 simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java diff --git a/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java b/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java index 6dfc9f4..dd0ab66 100644 --- a/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java +++ b/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java @@ -97,7 +97,7 @@ public void onClick(View v) { mCropView.setImageBitmap(getImageForIndex(mImageIndex)); break; case R.id.buttonRotateImage: - mCropView.rotateImage(CropImageView.RotateDegrees.ROTATE_90D); + mCropView.rotateImage(CropImageView.RotateDegrees.ROTATE_90D, true); break; } } diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java index fe8d34d..27da5eb 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java @@ -15,6 +15,7 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; @@ -23,6 +24,11 @@ import android.view.WindowManager; import android.widget.ImageView; +import com.isseiaoki.simplecropview.animation.SimpleValueAnimator; +import com.isseiaoki.simplecropview.animation.SimpleValueAnimatorListener; +import com.isseiaoki.simplecropview.animation.ValueAnimatorV14; +import com.isseiaoki.simplecropview.animation.ValueAnimatorV8; + public class CropImageView extends ImageView { private static final String TAG = CropImageView.class.getSimpleName(); @@ -57,6 +63,7 @@ public class CropImageView extends ImageView { private RectF mImageRect; private PointF mCenter = new PointF(); private float mLastX, mLastY; + private boolean mIsRotating = false; // Instance variables for customizable attributes ////////////////////////////////////////////// @@ -189,7 +196,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { - if (getDrawable() != null) initLayout(mViewWidth, mViewHeight); + if (getDrawable() != null) setupLayout(mViewWidth, mViewHeight); } @Override @@ -276,27 +283,29 @@ private void drawCropFrame(Canvas canvas) { if (mShowHandle) drawHandles(canvas); } - private void drawHandles(Canvas canvas) { - mPaintFrame.setStyle(Paint.Style.FILL); - mPaintFrame.setColor(mHandleColor); - canvas.drawCircle(mFrameRect.left, mFrameRect.top, mHandleSize, mPaintFrame); - canvas.drawCircle(mFrameRect.right, mFrameRect.top, mHandleSize, mPaintFrame); - canvas.drawCircle(mFrameRect.left, mFrameRect.bottom, mHandleSize, mPaintFrame); - canvas.drawCircle(mFrameRect.right, mFrameRect.bottom, mHandleSize, mPaintFrame); - } + private void drawOverlay(Canvas canvas) { + mPaintTransparent.setAntiAlias(true); + mPaintTransparent.setFilterBitmap(true); + mPaintTransparent.setColor(mOverlayColor); + mPaintTransparent.setStyle(Paint.Style.FILL); - private void drawGuidelines(Canvas canvas) { - mPaintFrame.setColor(mGuideColor); - mPaintFrame.setStrokeWidth(mGuideStrokeWeight); - float h1 = mFrameRect.left + (mFrameRect.right - mFrameRect.left) / 3.0f; - float h2 = mFrameRect.right - (mFrameRect.right - mFrameRect.left) / 3.0f; - float v1 = mFrameRect.top + (mFrameRect.bottom - mFrameRect.top) / 3.0f; - float v2 = mFrameRect.bottom - (mFrameRect.bottom - mFrameRect.top) / 3.0f; + if(mIsRotating){ - canvas.drawLine(h1, mFrameRect.top, h1, mFrameRect.bottom, mPaintFrame); - canvas.drawLine(h2, mFrameRect.top, h2, mFrameRect.bottom, mPaintFrame); - canvas.drawLine(mFrameRect.left, v1, mFrameRect.right, v1, mPaintFrame); - canvas.drawLine(mFrameRect.left, v2, mFrameRect.right, v2, mPaintFrame); + }else{ + Path path = new Path(); + if (mCropMode == CropMode.CIRCLE) { + path.addRect(mImageRect, Path.Direction.CW); + PointF circleCenter = new PointF((mFrameRect.left + mFrameRect.right) / 2, + (mFrameRect.top + mFrameRect.bottom) / 2); + float circleRadius = (mFrameRect.right - mFrameRect.left) / 2; + path.addCircle(circleCenter.x, circleCenter.y, circleRadius, Path.Direction.CCW); + canvas.drawPath(path, mPaintTransparent); + } else { + path.addRect(mImageRect, Path.Direction.CW); + path.addRect(mFrameRect, Path.Direction.CCW); + canvas.drawPath(path, mPaintTransparent); + } + } } private void drawFrame(Canvas canvas) { @@ -305,29 +314,40 @@ private void drawFrame(Canvas canvas) { mPaintFrame.setStyle(Paint.Style.STROKE); mPaintFrame.setColor(mFrameColor); mPaintFrame.setStrokeWidth(mFrameStrokeWeight); - canvas.drawRect(mFrameRect.left, mFrameRect.top, mFrameRect.right, mFrameRect.bottom, - mPaintFrame); + if(mIsRotating){ + + }else{ + canvas.drawRect(mFrameRect, mPaintFrame); + } } - private void drawOverlay(Canvas canvas) { - mPaintTransparent.setAntiAlias(true); - mPaintTransparent.setFilterBitmap(true); - mPaintTransparent.setColor(mOverlayColor); - mPaintTransparent.setStyle(Paint.Style.FILL); + private void drawGuidelines(Canvas canvas) { + mPaintFrame.setColor(mGuideColor); + mPaintFrame.setStrokeWidth(mGuideStrokeWeight); + if(mIsRotating){ + + }else{ + float h1 = mFrameRect.left + (mFrameRect.right - mFrameRect.left) / 3.0f; + float h2 = mFrameRect.right - (mFrameRect.right - mFrameRect.left) / 3.0f; + float v1 = mFrameRect.top + (mFrameRect.bottom - mFrameRect.top) / 3.0f; + float v2 = mFrameRect.bottom - (mFrameRect.bottom - mFrameRect.top) / 3.0f; + canvas.drawLine(h1, mFrameRect.top, h1, mFrameRect.bottom, mPaintFrame); + canvas.drawLine(h2, mFrameRect.top, h2, mFrameRect.bottom, mPaintFrame); + canvas.drawLine(mFrameRect.left, v1, mFrameRect.right, v1, mPaintFrame); + canvas.drawLine(mFrameRect.left, v2, mFrameRect.right, v2, mPaintFrame); + } + } - if (mCropMode == CropMode.CIRCLE) { - Path path = new Path(); - path.addRect(mImageRect.left, mImageRect.top, mImageRect.right, mImageRect.bottom, - Path.Direction.CW); - path.addCircle((mFrameRect.left + mFrameRect.right) / 2, - (mFrameRect.top + mFrameRect.bottom) / 2, - (mFrameRect.right - mFrameRect.left) / 2, Path.Direction.CCW); - canvas.drawPath(path, mPaintTransparent); - } else { - Path path = new Path(); - path.addRect(mImageRect.left, mImageRect.top, mImageRect.right, mImageRect.bottom, Path.Direction.CW); - path.addRect(mFrameRect.left, mFrameRect.top, mFrameRect.right, mFrameRect.bottom, Path.Direction.CCW); - canvas.drawPath(path, mPaintTransparent); + private void drawHandles(Canvas canvas) { + mPaintFrame.setStyle(Paint.Style.FILL); + mPaintFrame.setColor(mHandleColor); + if(mIsRotating){ + + }else{ + canvas.drawCircle(mFrameRect.left, mFrameRect.top, mHandleSize, mPaintFrame); + canvas.drawCircle(mFrameRect.right, mFrameRect.top, mHandleSize, mPaintFrame); + canvas.drawCircle(mFrameRect.left, mFrameRect.bottom, mHandleSize, mPaintFrame); + canvas.drawCircle(mFrameRect.right, mFrameRect.bottom, mHandleSize, mPaintFrame); } } @@ -338,51 +358,81 @@ private void setMatrix() { mMatrix.postRotate(mAngle, mCenter.x, mCenter.y); } - // Initializer ///////////////////////////////////////////////////////////////////////////////// + // Layout calculation ////////////////////////////////////////////////////////////////////////// + + private void setupLayout(int viewW, int viewH) { + if(viewW == 0 || viewH == 0)return; + setCenter(new PointF(getPaddingLeft() + viewW * 0.5f, getPaddingTop() + viewH * 0.5f)); + setScale(calcScale(viewW, viewH, mAngle)); + setMatrix(); + mImageRect = calcImageRect(0f, 0f, mImgWidth, mImgHeight, mMatrix); + mFrameRect = calcFrameRect(mImageRect); + invalidate(); + mIsInitialized = true; + } - private void initLayout(int viewW, int viewH) { + private float calcScale(int viewW, int viewH, float angle) { mImgWidth = getDrawable().getIntrinsicWidth(); mImgHeight = getDrawable().getIntrinsicHeight(); if (mImgWidth <= 0) mImgWidth = viewW; if (mImgHeight <= 0) mImgHeight = viewH; - float w = (float) viewW; - float h = (float) viewH; - float viewRatio = w / h; - float imgRatio = getRotatedWidth() / getRotatedHeight(); + float viewRatio = (float)viewW / (float)viewH; + float imgRatio = getRotatedWidth(angle) / getRotatedHeight(angle); float scale = 1.0f; if (imgRatio >= viewRatio) { - scale = w / getRotatedWidth(); + scale = viewW / getRotatedWidth(angle); } else if (imgRatio < viewRatio) { - scale = h / getRotatedHeight(); + scale = viewH / getRotatedHeight(angle); } - setCenter(new PointF(getPaddingLeft() + w * 0.5f, getPaddingTop() + h * 0.5f)); - setScale(scale); - initCropFrame(); - adjustRatio(); - mIsInitialized = true; + return scale; } - private void initCropFrame() { - setMatrix(); + private RectF calcImageRect(float left, float top, float right, float bottom, Matrix matrix){ float[] arrayOfFloat = new float[8]; - arrayOfFloat[0] = 0.0f; - arrayOfFloat[1] = 0.0f; - arrayOfFloat[2] = 0.0f; - arrayOfFloat[3] = mImgHeight; - arrayOfFloat[4] = mImgWidth; - arrayOfFloat[5] = 0.0f; - arrayOfFloat[6] = mImgWidth; - arrayOfFloat[7] = mImgHeight; - - mMatrix.mapPoints(arrayOfFloat); - + arrayOfFloat[0] = left; + arrayOfFloat[1] = top; + arrayOfFloat[2] = left; + arrayOfFloat[3] = bottom; + arrayOfFloat[4] = right; + arrayOfFloat[5] = top; + arrayOfFloat[6] = right; + arrayOfFloat[7] = bottom; + matrix.mapPoints(arrayOfFloat); float l = arrayOfFloat[0]; float t = arrayOfFloat[1]; float r = arrayOfFloat[6]; float b = arrayOfFloat[7]; + return new RectF(Math.min(l, r), Math.min(t, b), Math.max(l, r), Math.max(t, b)); + } - mFrameRect = new RectF(Math.min(l, r), Math.min(t, b), Math.max(l, r), Math.max(t, b)); - mImageRect = new RectF(Math.min(l, r), Math.min(t, b), Math.max(l, r), Math.max(t, b)); + private RectF calcFrameRect(RectF imageRect){ + float frameW = getRatioX(imageRect.width()); + float frameH = getRatioY(imageRect.height()); + float imgRatio = imageRect.width() / imageRect.height(); + float frameRatio = frameW / frameH; + float l = imageRect.left, t = imageRect.top, r = imageRect.right, b = imageRect.bottom; + if (frameRatio >= imgRatio) { + l = imageRect.left; + r = imageRect.right; + float hy = (imageRect.top + imageRect.bottom) * 0.5f; + float hh = (imageRect.width() / frameRatio) * 0.5f; + t = hy - hh; + b = hy + hh; + } else if (frameRatio < imgRatio) { + t = imageRect.top; + b = imageRect.bottom; + float hx = (imageRect.left + imageRect.right) * 0.5f; + float hw = imageRect.height() * frameRatio * 0.5f; + l = hx - hw; + r = hx + hw; + } + float w = r - l; + float h = b - t; + float cx = l + w / 2; + float cy = t + h / 2; + float sw = w * mInitialFrameScale; + float sh = h * mInitialFrameScale; + return new RectF(cx - sw / 2, cy - sh / 2, cx + sw / 2, cy + sh / 2); } // Touch Event ///////////////////////////////////////////////////////////////////////////////// @@ -391,6 +441,7 @@ private void initCropFrame() { public boolean onTouchEvent(MotionEvent event) { if (!mIsInitialized) return false; if (!mIsCropEnabled) return false; + if (mIsRotating) return false; if (!mIsEnabled) return false; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: @@ -534,12 +585,12 @@ private boolean isInsideCornerRightBottom(float x, float y) { return sq(mHandleSize + mTouchPadding) >= d; } - private float getRotatedWidth(){ - return mAngle % 180 == 0 ? mImgWidth : mImgHeight; + private float getRotatedWidth(float angle){ + return angle % 180 == 0 ? mImgWidth : mImgHeight; } - private float getRotatedHeight(){ - return mAngle % 180 == 0 ? mImgHeight : mImgWidth; + private float getRotatedHeight(float angle){ + return angle % 180 == 0 ? mImgHeight : mImgWidth; } @@ -800,35 +851,9 @@ private boolean isHeightTooSmall() { // Frame aspect ratio correction /////////////////////////////////////////////////////////////// - private void adjustRatio() { - if (mImageRect == null) return; - float frameW = getRatioX(mImageRect.width()); - float frameH = getRatioY(mImageRect.height()); - float imgRatio = mImageRect.width() / mImageRect.height(); - float frameRatio = frameW / frameH; - float l = mImageRect.left, t = mImageRect.top, r = mImageRect.right, b = mImageRect.bottom; - if (frameRatio >= imgRatio) { - l = mImageRect.left; - r = mImageRect.right; - float hy = (mImageRect.top + mImageRect.bottom) * 0.5f; - float hh = (mImageRect.width() / frameRatio) * 0.5f; - t = hy - hh; - b = hy + hh; - } else if (frameRatio < imgRatio) { - t = mImageRect.top; - b = mImageRect.bottom; - float hx = (mImageRect.left + mImageRect.right) * 0.5f; - float hw = mImageRect.height() * frameRatio * 0.5f; - l = hx - hw; - r = hx + hw; - } - float w = r - l; - float h = b - t; - float cx = l + w / 2; - float cy = t + h / 2; - float sw = w * mInitialFrameScale; - float sh = h * mInitialFrameScale; - mFrameRect = new RectF(cx - sw / 2, cy - sh / 2, cx + sw / 2, cy + sh / 2); + private void recalculateFrameRect() { + if(mImageRect == null) return; + mFrameRect = calcFrameRect(mImageRect); invalidate(); } @@ -1004,7 +1029,7 @@ private void updateDrawableInfo() { Drawable d = getDrawable(); mAngle = 0f; if (d != null) { - initLayout(mViewWidth, mViewHeight); + setupLayout(mViewWidth, mViewHeight); } } @@ -1014,8 +1039,55 @@ private void updateDrawableInfo() { * @param degrees angle of ration in degrees. */ public void rotateImage(RotateDegrees degrees) { - mAngle = (mAngle + degrees.getValue()) % 360; - initLayout(mViewWidth, mViewHeight); + rotateImage(degrees, false); + } + + public void rotateImage(RotateDegrees degrees, boolean animate){ + if(mIsRotating)return; + final float currentAngle = mAngle; + final float newAngle = (mAngle + degrees.getValue()); + final float angleDiff = newAngle - currentAngle; + final float currentScale = mScale; + final float newScale = calcScale(mViewWidth, mViewHeight, newAngle); + if(animate){ + final float scaleDiff = newScale - currentScale; + SimpleValueAnimator animator = getAnimator(); + animator.addAnimatorListener(new SimpleValueAnimatorListener() { + @Override + public void onAnimationStarted() { + mIsRotating = true; + } + + @Override + public void onAnimationUpdated(float scale) { + mAngle = currentAngle + angleDiff * scale; + mScale = currentScale + scaleDiff * scale; + setMatrix(); + invalidate(); + } + + @Override + public void onAnimationFinished() { + mAngle = newAngle % 360; + mScale = newScale; + setupLayout(mViewWidth, mViewHeight); + mIsRotating = false; + } + }); + animator.startAnimation(200); + }else{ + mAngle = newAngle % 360; + mScale = newScale; + setupLayout(mViewWidth, mViewHeight); + } + } + + public SimpleValueAnimator getAnimator(){ + if(Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH){ + return new ValueAnimatorV8(); + }else{ + return new ValueAnimatorV14(); + } } /** @@ -1149,7 +1221,7 @@ public void setCropMode(CropMode mode) { setCustomRatio(1, 1); } else { mCropMode = mode; - adjustRatio(); + recalculateFrameRect(); } } @@ -1163,7 +1235,7 @@ public void setCustomRatio(int ratioX, int ratioY) { if (ratioX == 0 || ratioY == 0) return; mCropMode = CropMode.RATIO_CUSTOM; mCustomRatio = new PointF(ratioX, ratioY); - adjustRatio(); + recalculateFrameRect(); } /** diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimator.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimator.java new file mode 100644 index 0000000..9f33644 --- /dev/null +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimator.java @@ -0,0 +1,8 @@ +package com.isseiaoki.simplecropview.animation; + +public interface SimpleValueAnimator { + public void startAnimation(long duration); + public void cancelAnimation(); + public boolean isAnimationStarted(); + public void addAnimatorListener(SimpleValueAnimatorListener animatorListener); +} diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimatorListener.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimatorListener.java new file mode 100644 index 0000000..e2569ce --- /dev/null +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimatorListener.java @@ -0,0 +1,7 @@ +package com.isseiaoki.simplecropview.animation; + +public interface SimpleValueAnimatorListener { + public void onAnimationStarted(); + public void onAnimationUpdated(float scale); + public void onAnimationFinished(); +} diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java new file mode 100644 index 0000000..630fa83 --- /dev/null +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java @@ -0,0 +1,83 @@ +package com.isseiaoki.simplecropview.animation; + +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; + +@SuppressLint("NewApi") +public class ValueAnimatorV14 implements SimpleValueAnimator, Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener { + private static final int DEFAULT_ANIMATION_DURATION = 300; + private ValueAnimator animator; + private SimpleValueAnimatorListener animatorListener = new SimpleValueAnimatorListener() { + @Override + public void onAnimationStarted() { + + } + + @Override + public void onAnimationUpdated(float scale) { + + } + + @Override + public void onAnimationFinished() { + + } + }; + + public ValueAnimatorV14(){ + animator = ValueAnimator.ofFloat(0.0f, 1.0f); + animator.addListener(this); + animator.addUpdateListener(this); + } + + @Override + public void startAnimation(long duration) { + if (duration >= 0) { + animator.setDuration(duration); + } else { + animator.setDuration(DEFAULT_ANIMATION_DURATION); + } + animator.start(); + } + + @Override + public void cancelAnimation() { + animator.cancel(); + } + + @Override + public boolean isAnimationStarted() { + return animator.isStarted(); + } + + @Override + public void addAnimatorListener(SimpleValueAnimatorListener animatorListener) { + if(animatorListener != null)this.animatorListener = animatorListener; + } + + @Override + public void onAnimationStart(Animator animation) { + animatorListener.onAnimationStarted(); + } + + @Override + public void onAnimationEnd(Animator animation) { + animatorListener.onAnimationFinished(); + } + + @Override + public void onAnimationCancel(Animator animation) { + animatorListener.onAnimationFinished(); + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + animatorListener.onAnimationUpdated(animation.getAnimatedFraction()); + } +} diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java new file mode 100644 index 0000000..635bbb8 --- /dev/null +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java @@ -0,0 +1,88 @@ +package com.isseiaoki.simplecropview.animation; + +import android.os.SystemClock; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.Interpolator; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class ValueAnimatorV8 implements SimpleValueAnimator{ + private static final int FRAME_RATE = 30; + private static final int UPDATE_SPAN = Math.round((float)1000/(float)FRAME_RATE); + private static final int DEFAULT_ANIMATION_DURATION = 300; + + final Interpolator interpolator = new AccelerateDecelerateInterpolator(); + ScheduledExecutorService service; + long start; + boolean isAnimationStarted = false; + long duration; + private SimpleValueAnimatorListener animatorListener = new SimpleValueAnimatorListener() { + @Override + public void onAnimationStarted() { + + } + + @Override + public void onAnimationUpdated(float scale) { + + } + + @Override + public void onAnimationFinished() { + + } + + }; + + private final Runnable runnable = new Runnable() { + @Override + public void run() { + long elapsed = SystemClock.uptimeMillis() - start; + if (elapsed > duration) { + isAnimationStarted = false; + animatorListener.onAnimationFinished(); + service.shutdown(); + return; + } + float scale = Math.min(interpolator.getInterpolation((float) elapsed / duration), 1); + animatorListener.onAnimationUpdated(scale); + } + }; + + public ValueAnimatorV8(){ + + } + + @Override + public void startAnimation(long duration) { + if (duration >= 0) { + this.duration = duration; + } else { + this.duration = DEFAULT_ANIMATION_DURATION; + } + isAnimationStarted = true; + animatorListener.onAnimationStarted(); + start = SystemClock.uptimeMillis(); + service = Executors.newSingleThreadScheduledExecutor(); + service.scheduleAtFixedRate(runnable, 0, UPDATE_SPAN, TimeUnit.MILLISECONDS); + } + + @Override + public void cancelAnimation() { + isAnimationStarted = false; + service.shutdown(); + animatorListener.onAnimationFinished(); + } + + @Override + public boolean isAnimationStarted() { + return isAnimationStarted; + } + + @Override + public void addAnimatorListener(SimpleValueAnimatorListener animatorListener) { + if(animatorListener != null)this.animatorListener = animatorListener; + } +} From 4ee3cb85ac6a9bdd59a976c9bc8661e8329bc0f4 Mon Sep 17 00:00:00 2001 From: Issei Aoki Date: Fri, 18 Mar 2016 18:45:20 +0900 Subject: [PATCH 03/35] Add params for animation --- .../simplecropviewsample/MainActivity.java | 2 +- .../simplecropview/CropImageView.java | 45 +++++++++++++++---- .../main/res/values/attrs_crop_image_view.xml | 2 + 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java b/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java index dd0ab66..6dfc9f4 100644 --- a/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java +++ b/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java @@ -97,7 +97,7 @@ public void onClick(View v) { mCropView.setImageBitmap(getImageForIndex(mImageIndex)); break; case R.id.buttonRotateImage: - mCropView.rotateImage(CropImageView.RotateDegrees.ROTATE_90D, true); + mCropView.rotateImage(CropImageView.RotateDegrees.ROTATE_90D); break; } } diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java index 27da5eb..48229b3 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java @@ -40,6 +40,7 @@ public class CropImageView extends ImageView { private static final int FRAME_STROKE_WEIGHT_IN_DP = 1; private static final int GUIDE_STROKE_WEIGHT_IN_DP = 1; private static final float DEFAULT_INITIAL_FRAME_SCALE = 0.75f; + private static final int DEFAULT_ANIMATION_DURATION_MILLIS = 500; private final int TRANSPARENT; private final int TRANSLUCENT_WHITE = 0xBBFFFFFF; @@ -87,6 +88,8 @@ public class CropImageView extends ImageView { private int mHandleColor; private int mGuideColor; private float mInitialFrameScale; // 0.01 ~ 1.0, 0.75 is default value + private boolean mIsAnimationEnabled = true; + private int mAnimationDuration = DEFAULT_ANIMATION_DURATION_MILLIS; // Constructor ///////////////////////////////////////////////////////////////////////////////// @@ -153,6 +156,8 @@ public Parcelable onSaveInstanceState() { ss.guideColor = this.mGuideColor; ss.initialFrameScale = this.mInitialFrameScale; ss.angle = this.mAngle; + ss.isAnimationEnabled = this.mIsAnimationEnabled; + ss.animationDuration = this.mAnimationDuration; return ss; } @@ -179,6 +184,8 @@ public void onRestoreInstanceState(Parcelable state) { this.mGuideColor = ss.guideColor; this.mInitialFrameScale = ss.initialFrameScale; this.mAngle = ss.angle; + this.mIsAnimationEnabled = ss.isAnimationEnabled; + this.mAnimationDuration = ss.animationDuration; setImageBitmap(ss.image); requestLayout(); } @@ -264,8 +271,10 @@ private void handleStyleable(Context context, AttributeSet attrs, int defStyle, (int) (GUIDE_STROKE_WEIGHT_IN_DP * mDensity)); mIsCropEnabled = ta.getBoolean(R.styleable.CropImageView_cropEnabled, true); mInitialFrameScale = constrain(ta.getFloat(R.styleable.CropImageView_initialFrameScale, - DEFAULT_INITIAL_FRAME_SCALE), 0.01f, 1.0f, - DEFAULT_INITIAL_FRAME_SCALE); + DEFAULT_INITIAL_FRAME_SCALE), 0.01f, 1.0f, + DEFAULT_INITIAL_FRAME_SCALE); + mIsAnimationEnabled = ta.getBoolean(R.styleable.CropImageView_animationEnabled, true); + mAnimationDuration = ta.getInt(R.styleable.CropImageView_animationDuration, DEFAULT_ANIMATION_DURATION_MILLIS); } catch (Exception e) { e.printStackTrace(); } finally { @@ -1038,18 +1047,14 @@ private void updateDrawableInfo() { * * @param degrees angle of ration in degrees. */ - public void rotateImage(RotateDegrees degrees) { - rotateImage(degrees, false); - } - - public void rotateImage(RotateDegrees degrees, boolean animate){ + public void rotateImage(RotateDegrees degrees){ if(mIsRotating)return; final float currentAngle = mAngle; final float newAngle = (mAngle + degrees.getValue()); final float angleDiff = newAngle - currentAngle; final float currentScale = mScale; final float newScale = calcScale(mViewWidth, mViewHeight, newAngle); - if(animate){ + if(mIsAnimationEnabled){ final float scaleDiff = newScale - currentScale; SimpleValueAnimator animator = getAnimator(); animator.addAnimatorListener(new SimpleValueAnimatorListener() { @@ -1074,7 +1079,7 @@ public void onAnimationFinished() { mIsRotating = false; } }); - animator.startAnimation(200); + animator.startAnimation(mAnimationDuration); }else{ mAngle = newAngle % 360; mScale = newScale; @@ -1416,6 +1421,22 @@ public void setInitialFrameScale(float initialScale) { mInitialFrameScale = constrain(initialScale, 0.01f, 1.0f, DEFAULT_INITIAL_FRAME_SCALE); } + /** + * Set whether to animate + * @param enabled + */ + public void setAnimationEnabled(boolean enabled){ + mIsAnimationEnabled = enabled; + } + + /** + * Set duration of animation + * @param duration + */ + public void setAnimationDuration(int duration){ + mAnimationDuration = duration; + } + private void setScale(float mScale) { this.mScale = mScale; } @@ -1503,6 +1524,8 @@ public static class SavedState extends BaseSavedState { int guideColor; float initialFrameScale; float angle; + boolean isAnimationEnabled; + int animationDuration; SavedState(Parcelable superState) { super(superState); @@ -1531,6 +1554,8 @@ private SavedState(Parcel in) { guideColor = in.readInt(); initialFrameScale = in.readFloat(); angle = in.readFloat(); + isAnimationEnabled = (in.readInt() != 0); + animationDuration = in.readInt(); } @Override @@ -1557,6 +1582,8 @@ public void writeToParcel(Parcel out, int flag) { out.writeInt(guideColor); out.writeFloat(initialFrameScale); out.writeFloat(angle); + out.writeInt(isAnimationEnabled ? 1 : 0); + out.writeInt(animationDuration); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { diff --git a/simplecropview/src/main/res/values/attrs_crop_image_view.xml b/simplecropview/src/main/res/values/attrs_crop_image_view.xml index dcea644..1a49ec5 100644 --- a/simplecropview/src/main/res/values/attrs_crop_image_view.xml +++ b/simplecropview/src/main/res/values/attrs_crop_image_view.xml @@ -35,5 +35,7 @@ + + \ No newline at end of file From 33f987cf67882c1376c9b807b38ce890a0fb6289 Mon Sep 17 00:00:00 2001 From: Issei Aoki Date: Fri, 18 Mar 2016 18:59:19 +0900 Subject: [PATCH 04/35] Add frame animation --- .../simplecropview/CropImageView.java | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java index 48229b3..ee91925 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java @@ -65,6 +65,7 @@ public class CropImageView extends ImageView { private PointF mCenter = new PointF(); private float mLastX, mLastY; private boolean mIsRotating = false; + private boolean mIsAnimating = false; // Instance variables for customizable attributes ////////////////////////////////////////////// @@ -450,8 +451,9 @@ private RectF calcFrameRect(RectF imageRect){ public boolean onTouchEvent(MotionEvent event) { if (!mIsInitialized) return false; if (!mIsCropEnabled) return false; - if (mIsRotating) return false; if (!mIsEnabled) return false; + if (mIsRotating) return false; + if (mIsAnimating) return false; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: onDown(event); @@ -862,8 +864,41 @@ private boolean isHeightTooSmall() { private void recalculateFrameRect() { if(mImageRect == null) return; - mFrameRect = calcFrameRect(mImageRect); - invalidate(); + final RectF currentRect = new RectF(mFrameRect); + final RectF newRect = calcFrameRect(mImageRect); + final float diffL = newRect.left - currentRect.left; + final float diffT = newRect.top - currentRect.top; + final float diffR = newRect.right - currentRect.right; + final float diffB = newRect.bottom - currentRect.bottom; + if(mIsAnimationEnabled){ + SimpleValueAnimator animator = getAnimator(); + animator.addAnimatorListener(new SimpleValueAnimatorListener() { + @Override + public void onAnimationStarted() { + mIsAnimating = true; + } + + @Override + public void onAnimationUpdated(float scale) { + mFrameRect = new RectF(currentRect.left + diffL * scale, + currentRect.top + diffT * scale, + currentRect.right + diffR * scale, + currentRect.bottom + diffB * scale); + invalidate(); + } + + @Override + public void onAnimationFinished() { + mFrameRect = newRect; + invalidate(); + mIsAnimating = false; + } + }); + animator.startAnimation(mAnimationDuration); + }else{ + mFrameRect = calcFrameRect(mImageRect); + invalidate(); + } } private float getRatioX(float w) { From 121d04f70e0c4c3af8820f33cdfdf562536b49df Mon Sep 17 00:00:00 2001 From: Issei Aoki Date: Tue, 22 Mar 2016 15:19:25 +0900 Subject: [PATCH 05/35] Modify default animation duration --- .../main/java/com/isseiaoki/simplecropview/CropImageView.java | 2 +- .../isseiaoki/simplecropview/animation/ValueAnimatorV14.java | 2 +- .../com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java index ee91925..9449dfd 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java @@ -40,7 +40,7 @@ public class CropImageView extends ImageView { private static final int FRAME_STROKE_WEIGHT_IN_DP = 1; private static final int GUIDE_STROKE_WEIGHT_IN_DP = 1; private static final float DEFAULT_INITIAL_FRAME_SCALE = 0.75f; - private static final int DEFAULT_ANIMATION_DURATION_MILLIS = 500; + private static final int DEFAULT_ANIMATION_DURATION_MILLIS = 150; private final int TRANSPARENT; private final int TRANSLUCENT_WHITE = 0xBBFFFFFF; diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java index 630fa83..bebd83b 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java @@ -6,7 +6,7 @@ @SuppressLint("NewApi") public class ValueAnimatorV14 implements SimpleValueAnimator, Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener { - private static final int DEFAULT_ANIMATION_DURATION = 300; + private static final int DEFAULT_ANIMATION_DURATION = 150; private ValueAnimator animator; private SimpleValueAnimatorListener animatorListener = new SimpleValueAnimatorListener() { @Override diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java index 635bbb8..8e1d512 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java @@ -11,7 +11,7 @@ public class ValueAnimatorV8 implements SimpleValueAnimator{ private static final int FRAME_RATE = 30; private static final int UPDATE_SPAN = Math.round((float)1000/(float)FRAME_RATE); - private static final int DEFAULT_ANIMATION_DURATION = 300; + private static final int DEFAULT_ANIMATION_DURATION = 150; final Interpolator interpolator = new AccelerateDecelerateInterpolator(); ScheduledExecutorService service; From cc001870d9f4aebd64a275335767d007e552ecb7 Mon Sep 17 00:00:00 2001 From: Issei Aoki Date: Tue, 22 Mar 2016 15:27:50 +0900 Subject: [PATCH 06/35] Fix frame animation with CropMode.CIRCLE --- .../main/java/com/isseiaoki/simplecropview/CropImageView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java index 9449dfd..b2443f4 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java @@ -303,7 +303,7 @@ private void drawOverlay(Canvas canvas) { }else{ Path path = new Path(); - if (mCropMode == CropMode.CIRCLE) { + if (!mIsAnimating && mCropMode == CropMode.CIRCLE) { path.addRect(mImageRect, Path.Direction.CW); PointF circleCenter = new PointF((mFrameRect.left + mFrameRect.right) / 2, (mFrameRect.top + mFrameRect.bottom) / 2); From 6a3782a76686249ca82d86e8cfb8619b8314d63d Mon Sep 17 00:00:00 2001 From: Issei Aoki Date: Tue, 22 Mar 2016 16:20:37 +0900 Subject: [PATCH 07/35] Add interpolator config and prevent animation until the previous animation finished --- .../simplecropview/CropImageView.java | 112 +++++++++++++----- .../animation/ValueAnimatorV14.java | 4 +- .../animation/ValueAnimatorV8.java | 8 +- 3 files changed, 90 insertions(+), 34 deletions(-) diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java index b2443f4..98058ca 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java @@ -22,6 +22,8 @@ import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.WindowManager; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.Interpolator; import android.widget.ImageView; import com.isseiaoki.simplecropview.animation.SimpleValueAnimator; @@ -46,6 +48,7 @@ public class CropImageView extends ImageView { private final int TRANSLUCENT_WHITE = 0xBBFFFFFF; private final int WHITE = 0xFFFFFFFF; private final int TRANSLUCENT_BLACK = 0xBB000000; + private final Interpolator DEFAULT_INTERPOLATOR = new AccelerateDecelerateInterpolator(); // Member variables //////////////////////////////////////////////////////////////////////////// @@ -66,6 +69,8 @@ public class CropImageView extends ImageView { private float mLastX, mLastY; private boolean mIsRotating = false; private boolean mIsAnimating = false; + private SimpleValueAnimator mAnimator = null; + private Interpolator mInterpolator = DEFAULT_INTERPOLATOR; // Instance variables for customizable attributes ////////////////////////////////////////////// @@ -90,7 +95,7 @@ public class CropImageView extends ImageView { private int mGuideColor; private float mInitialFrameScale; // 0.01 ~ 1.0, 0.75 is default value private boolean mIsAnimationEnabled = true; - private int mAnimationDuration = DEFAULT_ANIMATION_DURATION_MILLIS; + private int mAnimationDurationMillis = DEFAULT_ANIMATION_DURATION_MILLIS; // Constructor ///////////////////////////////////////////////////////////////////////////////// @@ -158,7 +163,7 @@ public Parcelable onSaveInstanceState() { ss.initialFrameScale = this.mInitialFrameScale; ss.angle = this.mAngle; ss.isAnimationEnabled = this.mIsAnimationEnabled; - ss.animationDuration = this.mAnimationDuration; + ss.animationDuration = this.mAnimationDurationMillis; return ss; } @@ -186,7 +191,7 @@ public void onRestoreInstanceState(Parcelable state) { this.mInitialFrameScale = ss.initialFrameScale; this.mAngle = ss.angle; this.mIsAnimationEnabled = ss.isAnimationEnabled; - this.mAnimationDuration = ss.animationDuration; + this.mAnimationDurationMillis = ss.animationDuration; setImageBitmap(ss.image); requestLayout(); } @@ -275,7 +280,7 @@ private void handleStyleable(Context context, AttributeSet attrs, int defStyle, DEFAULT_INITIAL_FRAME_SCALE), 0.01f, 1.0f, DEFAULT_INITIAL_FRAME_SCALE); mIsAnimationEnabled = ta.getBoolean(R.styleable.CropImageView_animationEnabled, true); - mAnimationDuration = ta.getInt(R.styleable.CropImageView_animationDuration, DEFAULT_ANIMATION_DURATION_MILLIS); + mAnimationDurationMillis = ta.getInt(R.styleable.CropImageView_animationDuration, DEFAULT_ANIMATION_DURATION_MILLIS); } catch (Exception e) { e.printStackTrace(); } finally { @@ -862,8 +867,11 @@ private boolean isHeightTooSmall() { // Frame aspect ratio correction /////////////////////////////////////////////////////////////// - private void recalculateFrameRect() { + private void recalculateFrameRect(int durationMillis) { if(mImageRect == null) return; + if(mIsAnimating){ + getAnimator().cancelAnimation(); + } final RectF currentRect = new RectF(mFrameRect); final RectF newRect = calcFrameRect(mImageRect); final float diffL = newRect.left - currentRect.left; @@ -894,7 +902,7 @@ public void onAnimationFinished() { mIsAnimating = false; } }); - animator.startAnimation(mAnimationDuration); + animator.startAnimation(durationMillis); }else{ mFrameRect = calcFrameRect(mImageRect); invalidate(); @@ -1078,12 +1086,14 @@ private void updateDrawableInfo() { } /** - * Rotate image. - * - * @param degrees angle of ration in degrees. + * Rotate image + * @param degrees + * @param durationMillis */ - public void rotateImage(RotateDegrees degrees){ - if(mIsRotating)return; + public void rotateImage(RotateDegrees degrees, int durationMillis){ + if(mIsRotating){ + getAnimator().cancelAnimation(); + } final float currentAngle = mAngle; final float newAngle = (mAngle + degrees.getValue()); final float angleDiff = newAngle - currentAngle; @@ -1114,7 +1124,7 @@ public void onAnimationFinished() { mIsRotating = false; } }); - animator.startAnimation(mAnimationDuration); + animator.startAnimation(durationMillis); }else{ mAngle = newAngle % 360; mScale = newScale; @@ -1122,14 +1132,30 @@ public void onAnimationFinished() { } } - public SimpleValueAnimator getAnimator(){ - if(Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH){ - return new ValueAnimatorV8(); - }else{ - return new ValueAnimatorV14(); + /** + * Rotate image + * @param degrees + */ + public void rotateImage(RotateDegrees degrees){ + rotateImage(degrees, mAnimationDurationMillis); + } + + private SimpleValueAnimator getAnimator(){ + setupAnimatorIfNeeded(); + return mAnimator; + } + + private void setupAnimatorIfNeeded() { + if(mAnimator == null){ + if(Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH){ + mAnimator = new ValueAnimatorV8(mInterpolator); + }else{ + mAnimator = new ValueAnimatorV14(mInterpolator); + } } } + /** * Get cropped image bitmap * @@ -1253,29 +1279,46 @@ public RectF getActualCropRect() { /** * Set crop mode - * - * @param mode crop mode + * @param mode + * @param durationMillis */ - public void setCropMode(CropMode mode) { + public void setCropMode(CropMode mode, int durationMillis) { if (mode == CropMode.RATIO_CUSTOM) { setCustomRatio(1, 1); } else { mCropMode = mode; - recalculateFrameRect(); + recalculateFrameRect(durationMillis); } } + /** + * Set crop mode + * @param mode + */ + public void setCropMode(CropMode mode){ + setCropMode(mode, mAnimationDurationMillis); + } + /** * Set custom aspect ratio to crop frame - * - * @param ratioX aspect ratio X - * @param ratioY aspect ratio Y + * @param ratioX + * @param ratioY + * @param durationMillis */ - public void setCustomRatio(int ratioX, int ratioY) { + public void setCustomRatio(int ratioX, int ratioY, int durationMillis) { if (ratioX == 0 || ratioY == 0) return; mCropMode = CropMode.RATIO_CUSTOM; mCustomRatio = new PointF(ratioX, ratioY); - recalculateFrameRect(); + recalculateFrameRect(durationMillis); + } + + /** + * Set custom aspect ratio to crop frame + * @param ratioX + * @param ratioY + */ + public void setCustomRatio(int ratioX, int ratioY) { + setCustomRatio(ratioX, ratioY, mAnimationDurationMillis); } /** @@ -1466,10 +1509,21 @@ public void setAnimationEnabled(boolean enabled){ /** * Set duration of animation - * @param duration + * @param durationMillis + */ + public void setAnimationDuration(int durationMillis){ + mAnimationDurationMillis = durationMillis; + } + + /** + * Set interpolator of animation + * (Default interpolator is AccelerateDecelerateInterpolator) + * @param interpolator */ - public void setAnimationDuration(int duration){ - mAnimationDuration = duration; + public void setInterpolator(Interpolator interpolator){ + mInterpolator = interpolator; + mAnimator = null; + setupAnimatorIfNeeded(); } private void setScale(float mScale) { diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java index bebd83b..7e18786 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java @@ -3,6 +3,7 @@ import android.animation.Animator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; +import android.view.animation.Interpolator; @SuppressLint("NewApi") public class ValueAnimatorV14 implements SimpleValueAnimator, Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener { @@ -25,10 +26,11 @@ public void onAnimationFinished() { } }; - public ValueAnimatorV14(){ + public ValueAnimatorV14(Interpolator interpolator){ animator = ValueAnimator.ofFloat(0.0f, 1.0f); animator.addListener(this); animator.addUpdateListener(this); + animator.setInterpolator(interpolator); } @Override diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java index 8e1d512..53221dc 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java @@ -13,7 +13,7 @@ public class ValueAnimatorV8 implements SimpleValueAnimator{ private static final int UPDATE_SPAN = Math.round((float)1000/(float)FRAME_RATE); private static final int DEFAULT_ANIMATION_DURATION = 150; - final Interpolator interpolator = new AccelerateDecelerateInterpolator(); + private Interpolator mInterpolator; ScheduledExecutorService service; long start; boolean isAnimationStarted = false; @@ -46,13 +46,13 @@ public void run() { service.shutdown(); return; } - float scale = Math.min(interpolator.getInterpolation((float) elapsed / duration), 1); + float scale = Math.min(mInterpolator.getInterpolation((float) elapsed / duration), 1); animatorListener.onAnimationUpdated(scale); } }; - public ValueAnimatorV8(){ - + public ValueAnimatorV8(Interpolator interpolator){ + this.mInterpolator = interpolator; } @Override From 11405b2b4905c320af9cc2b614b09b4564a1657c Mon Sep 17 00:00:00 2001 From: Issei Aoki Date: Tue, 22 Mar 2016 17:53:34 +0900 Subject: [PATCH 08/35] Refactor --- .../simplecropview/CropImageView.java | 137 +++++++++--------- 1 file changed, 65 insertions(+), 72 deletions(-) diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java index 98058ca..13077c0 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java @@ -232,7 +232,7 @@ public void onDraw(Canvas canvas) { private void handleStyleable(Context context, AttributeSet attrs, int defStyle, float mDensity) { TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CropImageView, defStyle, - 0); + 0); Drawable drawable; mCropMode = CropMode.RATIO_1_1; try { @@ -265,10 +265,10 @@ private void handleStyleable(Context context, AttributeSet attrs, int defStyle, setGuideShowMode(mGuideShowMode); setHandleShowMode(mHandleShowMode); mHandleSize = ta.getDimensionPixelSize(R.styleable.CropImageView_handleSize, - (int) (HANDLE_SIZE_IN_DP * mDensity)); + (int) (HANDLE_SIZE_IN_DP * mDensity)); mTouchPadding = ta.getDimensionPixelSize(R.styleable.CropImageView_touchPadding, 0); mMinFrameSize = ta.getDimensionPixelSize(R.styleable.CropImageView_minFrameSize, - (int) (MIN_FRAME_SIZE_IN_DP * mDensity)); + (int) (MIN_FRAME_SIZE_IN_DP * mDensity)); mFrameStrokeWeight = ta.getDimensionPixelSize( R.styleable.CropImageView_frameStrokeWeight, (int) (FRAME_STROKE_WEIGHT_IN_DP * mDensity)); @@ -292,6 +292,7 @@ private void handleStyleable(Context context, AttributeSet attrs, int defStyle, private void drawCropFrame(Canvas canvas) { if (!mIsCropEnabled) return; + if (mIsRotating) return; drawOverlay(canvas); drawFrame(canvas); if (mShowGuide) drawGuidelines(canvas); @@ -303,23 +304,18 @@ private void drawOverlay(Canvas canvas) { mPaintTransparent.setFilterBitmap(true); mPaintTransparent.setColor(mOverlayColor); mPaintTransparent.setStyle(Paint.Style.FILL); - - if(mIsRotating){ - - }else{ - Path path = new Path(); - if (!mIsAnimating && mCropMode == CropMode.CIRCLE) { - path.addRect(mImageRect, Path.Direction.CW); - PointF circleCenter = new PointF((mFrameRect.left + mFrameRect.right) / 2, - (mFrameRect.top + mFrameRect.bottom) / 2); - float circleRadius = (mFrameRect.right - mFrameRect.left) / 2; - path.addCircle(circleCenter.x, circleCenter.y, circleRadius, Path.Direction.CCW); - canvas.drawPath(path, mPaintTransparent); - } else { - path.addRect(mImageRect, Path.Direction.CW); - path.addRect(mFrameRect, Path.Direction.CCW); - canvas.drawPath(path, mPaintTransparent); - } + Path path = new Path(); + if (!mIsAnimating && mCropMode == CropMode.CIRCLE) { + path.addRect(mImageRect, Path.Direction.CW); + PointF circleCenter = new PointF((mFrameRect.left + mFrameRect.right) / 2, + (mFrameRect.top + mFrameRect.bottom) / 2); + float circleRadius = (mFrameRect.right - mFrameRect.left) / 2; + path.addCircle(circleCenter.x, circleCenter.y, circleRadius, Path.Direction.CCW); + canvas.drawPath(path, mPaintTransparent); + } else { + path.addRect(mImageRect, Path.Direction.CW); + path.addRect(mFrameRect, Path.Direction.CCW); + canvas.drawPath(path, mPaintTransparent); } } @@ -329,41 +325,29 @@ private void drawFrame(Canvas canvas) { mPaintFrame.setStyle(Paint.Style.STROKE); mPaintFrame.setColor(mFrameColor); mPaintFrame.setStrokeWidth(mFrameStrokeWeight); - if(mIsRotating){ - - }else{ - canvas.drawRect(mFrameRect, mPaintFrame); - } + canvas.drawRect(mFrameRect, mPaintFrame); } private void drawGuidelines(Canvas canvas) { mPaintFrame.setColor(mGuideColor); mPaintFrame.setStrokeWidth(mGuideStrokeWeight); - if(mIsRotating){ - - }else{ - float h1 = mFrameRect.left + (mFrameRect.right - mFrameRect.left) / 3.0f; - float h2 = mFrameRect.right - (mFrameRect.right - mFrameRect.left) / 3.0f; - float v1 = mFrameRect.top + (mFrameRect.bottom - mFrameRect.top) / 3.0f; - float v2 = mFrameRect.bottom - (mFrameRect.bottom - mFrameRect.top) / 3.0f; - canvas.drawLine(h1, mFrameRect.top, h1, mFrameRect.bottom, mPaintFrame); - canvas.drawLine(h2, mFrameRect.top, h2, mFrameRect.bottom, mPaintFrame); - canvas.drawLine(mFrameRect.left, v1, mFrameRect.right, v1, mPaintFrame); - canvas.drawLine(mFrameRect.left, v2, mFrameRect.right, v2, mPaintFrame); - } + float h1 = mFrameRect.left + (mFrameRect.right - mFrameRect.left) / 3.0f; + float h2 = mFrameRect.right - (mFrameRect.right - mFrameRect.left) / 3.0f; + float v1 = mFrameRect.top + (mFrameRect.bottom - mFrameRect.top) / 3.0f; + float v2 = mFrameRect.bottom - (mFrameRect.bottom - mFrameRect.top) / 3.0f; + canvas.drawLine(h1, mFrameRect.top, h1, mFrameRect.bottom, mPaintFrame); + canvas.drawLine(h2, mFrameRect.top, h2, mFrameRect.bottom, mPaintFrame); + canvas.drawLine(mFrameRect.left, v1, mFrameRect.right, v1, mPaintFrame); + canvas.drawLine(mFrameRect.left, v2, mFrameRect.right, v2, mPaintFrame); } private void drawHandles(Canvas canvas) { mPaintFrame.setStyle(Paint.Style.FILL); mPaintFrame.setColor(mHandleColor); - if(mIsRotating){ - - }else{ - canvas.drawCircle(mFrameRect.left, mFrameRect.top, mHandleSize, mPaintFrame); - canvas.drawCircle(mFrameRect.right, mFrameRect.top, mHandleSize, mPaintFrame); - canvas.drawCircle(mFrameRect.left, mFrameRect.bottom, mHandleSize, mPaintFrame); - canvas.drawCircle(mFrameRect.right, mFrameRect.bottom, mHandleSize, mPaintFrame); - } + canvas.drawCircle(mFrameRect.left, mFrameRect.top, mHandleSize, mPaintFrame); + canvas.drawCircle(mFrameRect.right, mFrameRect.top, mHandleSize, mPaintFrame); + canvas.drawCircle(mFrameRect.left, mFrameRect.bottom, mHandleSize, mPaintFrame); + canvas.drawCircle(mFrameRect.right, mFrameRect.bottom, mHandleSize, mPaintFrame); } private void setMatrix() { @@ -376,7 +360,7 @@ private void setMatrix() { // Layout calculation ////////////////////////////////////////////////////////////////////////// private void setupLayout(int viewW, int viewH) { - if(viewW == 0 || viewH == 0)return; + if (viewW == 0 || viewH == 0) return; setCenter(new PointF(getPaddingLeft() + viewW * 0.5f, getPaddingTop() + viewH * 0.5f)); setScale(calcScale(viewW, viewH, mAngle)); setMatrix(); @@ -391,7 +375,7 @@ private float calcScale(int viewW, int viewH, float angle) { mImgHeight = getDrawable().getIntrinsicHeight(); if (mImgWidth <= 0) mImgWidth = viewW; if (mImgHeight <= 0) mImgHeight = viewH; - float viewRatio = (float)viewW / (float)viewH; + float viewRatio = (float) viewW / (float) viewH; float imgRatio = getRotatedWidth(angle) / getRotatedHeight(angle); float scale = 1.0f; if (imgRatio >= viewRatio) { @@ -402,7 +386,7 @@ private float calcScale(int viewW, int viewH, float angle) { return scale; } - private RectF calcImageRect(float left, float top, float right, float bottom, Matrix matrix){ + private RectF calcImageRect(float left, float top, float right, float bottom, Matrix matrix) { float[] arrayOfFloat = new float[8]; arrayOfFloat[0] = left; arrayOfFloat[1] = top; @@ -420,7 +404,7 @@ private RectF calcImageRect(float left, float top, float right, float bottom, Ma return new RectF(Math.min(l, r), Math.min(t, b), Math.max(l, r), Math.max(t, b)); } - private RectF calcFrameRect(RectF imageRect){ + private RectF calcFrameRect(RectF imageRect) { float frameW = getRatioX(imageRect.width()); float frameH = getRatioY(imageRect.height()); float imgRatio = imageRect.width() / imageRect.height(); @@ -601,11 +585,11 @@ private boolean isInsideCornerRightBottom(float x, float y) { return sq(mHandleSize + mTouchPadding) >= d; } - private float getRotatedWidth(float angle){ + private float getRotatedWidth(float angle) { return angle % 180 == 0 ? mImgWidth : mImgHeight; } - private float getRotatedHeight(float angle){ + private float getRotatedHeight(float angle) { return angle % 180 == 0 ? mImgHeight : mImgWidth; } @@ -868,8 +852,8 @@ private boolean isHeightTooSmall() { // Frame aspect ratio correction /////////////////////////////////////////////////////////////// private void recalculateFrameRect(int durationMillis) { - if(mImageRect == null) return; - if(mIsAnimating){ + if (mImageRect == null) return; + if (mIsAnimating) { getAnimator().cancelAnimation(); } final RectF currentRect = new RectF(mFrameRect); @@ -878,7 +862,7 @@ private void recalculateFrameRect(int durationMillis) { final float diffT = newRect.top - currentRect.top; final float diffR = newRect.right - currentRect.right; final float diffB = newRect.bottom - currentRect.bottom; - if(mIsAnimationEnabled){ + if (mIsAnimationEnabled) { SimpleValueAnimator animator = getAnimator(); animator.addAnimatorListener(new SimpleValueAnimatorListener() { @Override @@ -903,7 +887,7 @@ public void onAnimationFinished() { } }); animator.startAnimation(durationMillis); - }else{ + } else { mFrameRect = calcFrameRect(mImageRect); invalidate(); } @@ -1087,11 +1071,12 @@ private void updateDrawableInfo() { /** * Rotate image + * * @param degrees * @param durationMillis */ - public void rotateImage(RotateDegrees degrees, int durationMillis){ - if(mIsRotating){ + public void rotateImage(RotateDegrees degrees, int durationMillis) { + if (mIsRotating) { getAnimator().cancelAnimation(); } final float currentAngle = mAngle; @@ -1099,7 +1084,7 @@ public void rotateImage(RotateDegrees degrees, int durationMillis){ final float angleDiff = newAngle - currentAngle; final float currentScale = mScale; final float newScale = calcScale(mViewWidth, mViewHeight, newAngle); - if(mIsAnimationEnabled){ + if (mIsAnimationEnabled) { final float scaleDiff = newScale - currentScale; SimpleValueAnimator animator = getAnimator(); animator.addAnimatorListener(new SimpleValueAnimatorListener() { @@ -1125,7 +1110,7 @@ public void onAnimationFinished() { } }); animator.startAnimation(durationMillis); - }else{ + } else { mAngle = newAngle % 360; mScale = newScale; setupLayout(mViewWidth, mViewHeight); @@ -1134,22 +1119,23 @@ public void onAnimationFinished() { /** * Rotate image + * * @param degrees */ - public void rotateImage(RotateDegrees degrees){ + public void rotateImage(RotateDegrees degrees) { rotateImage(degrees, mAnimationDurationMillis); } - private SimpleValueAnimator getAnimator(){ + private SimpleValueAnimator getAnimator() { setupAnimatorIfNeeded(); return mAnimator; } private void setupAnimatorIfNeeded() { - if(mAnimator == null){ - if(Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH){ - mAnimator = new ValueAnimatorV8(mInterpolator); - }else{ + if (mAnimator == null) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + mAnimator = new ValueAnimatorV8(mInterpolator); + } else { mAnimator = new ValueAnimatorV14(mInterpolator); } } @@ -1166,7 +1152,7 @@ public Bitmap getCroppedBitmap() { if (source == null) return null; Matrix rotateMatrix = new Matrix(); - rotateMatrix.setRotate(mAngle, source.getWidth() / 2, source.getHeight()/2); + rotateMatrix.setRotate(mAngle, source.getWidth() / 2, source.getHeight() / 2); Bitmap rotated = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), rotateMatrix, true); int x, y, w, h; @@ -1204,7 +1190,7 @@ public Bitmap getRectBitmap() { if (source == null) return null; Matrix rotateMatrix = new Matrix(); - rotateMatrix.setRotate(mAngle, source.getWidth() / 2, source.getHeight()/2); + rotateMatrix.setRotate(mAngle, source.getWidth() / 2, source.getHeight() / 2); Bitmap rotated = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), rotateMatrix, true); int x, y, w, h; @@ -1236,7 +1222,7 @@ public Bitmap getRectBitmap() { public Bitmap getCircularBitmap(Bitmap square) { if (square == null) return null; Bitmap output = Bitmap.createBitmap(square.getWidth(), square.getHeight(), - Bitmap.Config.ARGB_8888); + Bitmap.Config.ARGB_8888); final Rect rect = new Rect(0, 0, square.getWidth(), square.getHeight()); Canvas canvas = new Canvas(output); @@ -1279,6 +1265,7 @@ public RectF getActualCropRect() { /** * Set crop mode + * * @param mode * @param durationMillis */ @@ -1293,14 +1280,16 @@ public void setCropMode(CropMode mode, int durationMillis) { /** * Set crop mode + * * @param mode */ - public void setCropMode(CropMode mode){ + public void setCropMode(CropMode mode) { setCropMode(mode, mAnimationDurationMillis); } /** * Set custom aspect ratio to crop frame + * * @param ratioX * @param ratioY * @param durationMillis @@ -1314,6 +1303,7 @@ public void setCustomRatio(int ratioX, int ratioY, int durationMillis) { /** * Set custom aspect ratio to crop frame + * * @param ratioX * @param ratioY */ @@ -1501,26 +1491,29 @@ public void setInitialFrameScale(float initialScale) { /** * Set whether to animate + * * @param enabled */ - public void setAnimationEnabled(boolean enabled){ + public void setAnimationEnabled(boolean enabled) { mIsAnimationEnabled = enabled; } /** * Set duration of animation + * * @param durationMillis */ - public void setAnimationDuration(int durationMillis){ + public void setAnimationDuration(int durationMillis) { mAnimationDurationMillis = durationMillis; } /** * Set interpolator of animation * (Default interpolator is AccelerateDecelerateInterpolator) + * * @param interpolator */ - public void setInterpolator(Interpolator interpolator){ + public void setInterpolator(Interpolator interpolator) { mInterpolator = interpolator; mAnimator = null; setupAnimatorIfNeeded(); From ca062306e926202f3d70c6f3259d236ab834c5d9 Mon Sep 17 00:00:00 2001 From: Issei Aoki Date: Wed, 23 Mar 2016 14:24:41 +0900 Subject: [PATCH 09/35] Fix lint warnings --- .../src/main/AndroidManifest.xml | 1 + .../simplecropviewsample/AppController.java | 2 +- .../simplecropviewsample/FontUtils.java | 21 ++++---- simplecropview/src/main/AndroidManifest.xml | 4 +- .../simplecropview/CropImageView.java | 52 ++++++++++--------- .../animation/SimpleValueAnimator.java | 10 ++-- .../SimpleValueAnimatorListener.java | 6 +-- .../animation/ValueAnimatorV14.java | 5 +- .../animation/ValueAnimatorV8.java | 9 ++-- 9 files changed, 54 insertions(+), 56 deletions(-) diff --git a/simplecropview-sample/src/main/AndroidManifest.xml b/simplecropview-sample/src/main/AndroidManifest.xml index d7bdc64..11c5a66 100644 --- a/simplecropview-sample/src/main/AndroidManifest.xml +++ b/simplecropview-sample/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ 0) { bos.write(buffer, 0, length); } @@ -92,8 +91,6 @@ public static Typeface getTypefaceFromRaw(Context context, int resourceId) { // When loading completed, delete temporary files typeface = Typeface.createFromFile(fontFilePath); new File(fontFilePath).delete(); - } catch (Resources.NotFoundException e) { - e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { diff --git a/simplecropview/src/main/AndroidManifest.xml b/simplecropview/src/main/AndroidManifest.xml index 8163dfc..9ee5b48 100644 --- a/simplecropview/src/main/AndroidManifest.xml +++ b/simplecropview/src/main/AndroidManifest.xml @@ -1,3 +1 @@ - - + diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java index 13077c0..fe912f9 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java @@ -31,7 +31,7 @@ import com.isseiaoki.simplecropview.animation.ValueAnimatorV14; import com.isseiaoki.simplecropview.animation.ValueAnimatorV8; - +@SuppressWarnings("unused") public class CropImageView extends ImageView { private static final String TAG = CropImageView.class.getSimpleName(); @@ -44,7 +44,7 @@ public class CropImageView extends ImageView { private static final float DEFAULT_INITIAL_FRAME_SCALE = 0.75f; private static final int DEFAULT_ANIMATION_DURATION_MILLIS = 150; - private final int TRANSPARENT; + private final int TRANSPARENT = 0x00000000; private final int TRANSLUCENT_WHITE = 0xBBFFFFFF; private final int WHITE = 0xFFFFFFFF; private final int TRANSLUCENT_BLACK = 0xBB000000; @@ -109,7 +109,6 @@ public CropImageView(Context context, AttributeSet attrs) { public CropImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - TRANSPARENT = getResources().getColor(android.R.color.transparent); float mDensity = getDensity(); mHandleSize = (int) (mDensity * HANDLE_SIZE_IN_DP); @@ -140,8 +139,7 @@ public CropImageView(Context context, AttributeSet attrs, int defStyle) { public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); - Bitmap bm = getBitmap(); - ss.image = bm; + ss.image = getBitmap(); ss.mode = this.mCropMode; ss.backgroundColor = this.mBackgroundColor; ss.overlayColor = this.mOverlayColor; @@ -604,6 +602,7 @@ private void moveFrame(float x, float y) { checkMoveBounds(); } + @SuppressWarnings("UnnecessaryLocalVariable") private void moveHandleLT(float diffX, float diffY) { if (mCropMode == CropMode.RATIO_FREE) { mFrameRect.left += diffX; @@ -650,6 +649,7 @@ private void moveHandleLT(float diffX, float diffY) { } } + @SuppressWarnings("UnnecessaryLocalVariable") private void moveHandleRT(float diffX, float diffY) { if (mCropMode == CropMode.RATIO_FREE) { mFrameRect.right += diffX; @@ -696,6 +696,7 @@ private void moveHandleRT(float diffX, float diffY) { } } + @SuppressWarnings("UnnecessaryLocalVariable") private void moveHandleLB(float diffX, float diffY) { if (mCropMode == CropMode.RATIO_FREE) { mFrameRect.left += diffX; @@ -742,6 +743,7 @@ private void moveHandleLB(float diffX, float diffY) { } } + @SuppressWarnings("UnnecessaryLocalVariable") private void moveHandleRB(float diffX, float diffY) { if (mCropMode == CropMode.RATIO_FREE) { mFrameRect.right += diffX; @@ -1040,7 +1042,7 @@ public void setImageResource(int resId) { /** * Set image drawable. * - * @param drawable + * @param drawable source image drawable */ @Override public void setImageDrawable(Drawable drawable) { @@ -1052,7 +1054,7 @@ public void setImageDrawable(Drawable drawable) { /** * Set image uri * - * @param uri + * @param uri source image local uri */ @Override public void setImageURI(Uri uri) { @@ -1072,8 +1074,8 @@ private void updateDrawableInfo() { /** * Rotate image * - * @param degrees - * @param durationMillis + * @param degrees rotation angle + * @param durationMillis animation duration in milliseconds */ public void rotateImage(RotateDegrees degrees, int durationMillis) { if (mIsRotating) { @@ -1120,7 +1122,7 @@ public void onAnimationFinished() { /** * Rotate image * - * @param degrees + * @param degrees rotation angle */ public void rotateImage(RotateDegrees degrees) { rotateImage(degrees, mAnimationDurationMillis); @@ -1266,8 +1268,8 @@ public RectF getActualCropRect() { /** * Set crop mode * - * @param mode - * @param durationMillis + * @param mode crop mode + * @param durationMillis animation duration in milliseconds */ public void setCropMode(CropMode mode, int durationMillis) { if (mode == CropMode.RATIO_CUSTOM) { @@ -1281,7 +1283,7 @@ public void setCropMode(CropMode mode, int durationMillis) { /** * Set crop mode * - * @param mode + * @param mode crop mode */ public void setCropMode(CropMode mode) { setCropMode(mode, mAnimationDurationMillis); @@ -1290,9 +1292,9 @@ public void setCropMode(CropMode mode) { /** * Set custom aspect ratio to crop frame * - * @param ratioX - * @param ratioY - * @param durationMillis + * @param ratioX ratio x + * @param ratioY ratio y + * @param durationMillis animation duration in milliseconds */ public void setCustomRatio(int ratioX, int ratioY, int durationMillis) { if (ratioX == 0 || ratioY == 0) return; @@ -1304,8 +1306,8 @@ public void setCustomRatio(int ratioX, int ratioY, int durationMillis) { /** * Set custom aspect ratio to crop frame * - * @param ratioX - * @param ratioY + * @param ratioX ratio x + * @param ratioY ratio y */ public void setCustomRatio(int ratioX, int ratioY) { setCustomRatio(ratioX, ratioY, mAnimationDurationMillis); @@ -1492,7 +1494,7 @@ public void setInitialFrameScale(float initialScale) { /** * Set whether to animate * - * @param enabled + * @param enabled is animation enabled */ public void setAnimationEnabled(boolean enabled) { mIsAnimationEnabled = enabled; @@ -1501,7 +1503,7 @@ public void setAnimationEnabled(boolean enabled) { /** * Set duration of animation * - * @param durationMillis + * @param durationMillis animation duration in milliseconds */ public void setAnimationDuration(int durationMillis) { mAnimationDurationMillis = durationMillis; @@ -1511,7 +1513,7 @@ public void setAnimationDuration(int durationMillis) { * Set interpolator of animation * (Default interpolator is AccelerateDecelerateInterpolator) * - * @param interpolator + * @param interpolator interpolator used for animation */ public void setInterpolator(Interpolator interpolator) { mInterpolator = interpolator; @@ -1538,7 +1540,7 @@ private float getFrameH() { // Enum //////////////////////////////////////////////////////////////////////////////////////// private enum TouchArea { - OUT_OF_BOUNDS, CENTER, LEFT_TOP, RIGHT_TOP, LEFT_BOTTOM, RIGHT_BOTTOM; + OUT_OF_BOUNDS, CENTER, LEFT_TOP, RIGHT_TOP, LEFT_BOTTOM, RIGHT_BOTTOM } public enum CropMode { @@ -1546,7 +1548,7 @@ public enum CropMode { 5), RATIO_FREE(6), RATIO_CUSTOM(7), CIRCLE(8); private final int ID; - private CropMode(final int id) { + CropMode(final int id) { this.ID = id; } @@ -1559,7 +1561,7 @@ public enum ShowMode { SHOW_ALWAYS(1), SHOW_ON_TOUCH(2), NOT_SHOW(3); private final int ID; - private ShowMode(final int id) { + ShowMode(final int id) { this.ID = id; } @@ -1573,7 +1575,7 @@ public enum RotateDegrees { private final int VALUE; - private RotateDegrees(final int value) { + RotateDegrees(final int value) { this.VALUE = value; } diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimator.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimator.java index 9f33644..9ebf55f 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimator.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimator.java @@ -1,8 +1,8 @@ package com.isseiaoki.simplecropview.animation; - +@SuppressWarnings("unused") public interface SimpleValueAnimator { - public void startAnimation(long duration); - public void cancelAnimation(); - public boolean isAnimationStarted(); - public void addAnimatorListener(SimpleValueAnimatorListener animatorListener); + void startAnimation(long duration); + void cancelAnimation(); + boolean isAnimationStarted(); + void addAnimatorListener(SimpleValueAnimatorListener animatorListener); } diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimatorListener.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimatorListener.java index e2569ce..7e3d459 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimatorListener.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/SimpleValueAnimatorListener.java @@ -1,7 +1,7 @@ package com.isseiaoki.simplecropview.animation; public interface SimpleValueAnimatorListener { - public void onAnimationStarted(); - public void onAnimationUpdated(float scale); - public void onAnimationFinished(); + void onAnimationStarted(); + void onAnimationUpdated(float scale); + void onAnimationFinished(); } diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java index 7e18786..cb3ae41 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV14.java @@ -2,10 +2,11 @@ import android.animation.Animator; import android.animation.ValueAnimator; -import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.os.Build; import android.view.animation.Interpolator; -@SuppressLint("NewApi") +@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public class ValueAnimatorV14 implements SimpleValueAnimator, Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener { private static final int DEFAULT_ANIMATION_DURATION = 150; private ValueAnimator animator; diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java index 53221dc..200a8e9 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/animation/ValueAnimatorV8.java @@ -1,16 +1,15 @@ package com.isseiaoki.simplecropview.animation; import android.os.SystemClock; -import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -public class ValueAnimatorV8 implements SimpleValueAnimator{ +public class ValueAnimatorV8 implements SimpleValueAnimator { private static final int FRAME_RATE = 30; - private static final int UPDATE_SPAN = Math.round((float)1000/(float)FRAME_RATE); + private static final int UPDATE_SPAN = Math.round((float) 1000 / (float) FRAME_RATE); private static final int DEFAULT_ANIMATION_DURATION = 150; private Interpolator mInterpolator; @@ -51,7 +50,7 @@ public void run() { } }; - public ValueAnimatorV8(Interpolator interpolator){ + public ValueAnimatorV8(Interpolator interpolator) { this.mInterpolator = interpolator; } @@ -83,6 +82,6 @@ public boolean isAnimationStarted() { @Override public void addAnimatorListener(SimpleValueAnimatorListener animatorListener) { - if(animatorListener != null)this.animatorListener = animatorListener; + if (animatorListener != null) this.animatorListener = animatorListener; } } From 106b1aa467d9c83556bfccab54bcf0b2e6932365 Mon Sep 17 00:00:00 2001 From: Issei Aoki Date: Wed, 23 Mar 2016 14:56:12 +0900 Subject: [PATCH 10/35] Refactor --- .../isseiaoki/simplecropview/CropImageView.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java index fe912f9..fc6c6de 100644 --- a/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java +++ b/simplecropview/src/main/java/com/isseiaoki/simplecropview/CropImageView.java @@ -60,7 +60,7 @@ public class CropImageView extends ImageView { private float mImgHeight = 0.0f; private boolean mIsInitialized = false; private Matrix mMatrix = null; - private Paint mPaintTransparent; + private Paint mPaintTranslucent; private Paint mPaintFrame; private Paint mPaintBitmap; private RectF mFrameRect; @@ -117,7 +117,7 @@ public CropImageView(Context context, AttributeSet attrs, int defStyle) { mGuideStrokeWeight = mDensity * GUIDE_STROKE_WEIGHT_IN_DP; mPaintFrame = new Paint(); - mPaintTransparent = new Paint(); + mPaintTranslucent = new Paint(); mPaintBitmap = new Paint(); mPaintBitmap.setFilterBitmap(true); @@ -298,10 +298,10 @@ private void drawCropFrame(Canvas canvas) { } private void drawOverlay(Canvas canvas) { - mPaintTransparent.setAntiAlias(true); - mPaintTransparent.setFilterBitmap(true); - mPaintTransparent.setColor(mOverlayColor); - mPaintTransparent.setStyle(Paint.Style.FILL); + mPaintTranslucent.setAntiAlias(true); + mPaintTranslucent.setFilterBitmap(true); + mPaintTranslucent.setColor(mOverlayColor); + mPaintTranslucent.setStyle(Paint.Style.FILL); Path path = new Path(); if (!mIsAnimating && mCropMode == CropMode.CIRCLE) { path.addRect(mImageRect, Path.Direction.CW); @@ -309,11 +309,11 @@ private void drawOverlay(Canvas canvas) { (mFrameRect.top + mFrameRect.bottom) / 2); float circleRadius = (mFrameRect.right - mFrameRect.left) / 2; path.addCircle(circleCenter.x, circleCenter.y, circleRadius, Path.Direction.CCW); - canvas.drawPath(path, mPaintTransparent); + canvas.drawPath(path, mPaintTranslucent); } else { path.addRect(mImageRect, Path.Direction.CW); path.addRect(mFrameRect, Path.Direction.CCW); - canvas.drawPath(path, mPaintTransparent); + canvas.drawPath(path, mPaintTranslucent); } } From 50302815ddd06b4411c5af30d81b31ab231eabb7 Mon Sep 17 00:00:00 2001 From: Issei Aoki Date: Wed, 23 Mar 2016 15:14:14 +0900 Subject: [PATCH 11/35] Add SHOW_CIRCLE_BUT_CROP_AS_SQUARE and remove getRectBitmap() --- .../simplecropviewsample/MainActivity.java | 4 ++ .../src/main/res/layout/activity_main.xml | 11 +++++ .../simplecropview/CropImageView.java | 44 +++---------------- 3 files changed, 21 insertions(+), 38 deletions(-) diff --git a/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java b/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java index 6dfc9f4..b7ffc23 100644 --- a/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java +++ b/simplecropview-sample/src/main/java/com/example/simplecropviewsample/MainActivity.java @@ -92,6 +92,9 @@ public void onClick(View v) { case R.id.buttonCircle: mCropView.setCropMode(CropImageView.CropMode.CIRCLE); break; + case R.id.buttonShowCircleButCropAsSquare: + mCropView.setCropMode(CropImageView.CropMode.SHOW_CIRCLE_BUT_CROP_AS_SQUARE); + break; case R.id.buttonChangeImage: incrementImageIndex(); mCropView.setImageBitmap(getImageForIndex(mImageIndex)); @@ -119,6 +122,7 @@ private void findViews() { findViewById(R.id.buttonRotateImage).setOnClickListener(btnListener); findViewById(R.id.buttonCustom).setOnClickListener(btnListener); findViewById(R.id.buttonCircle).setOnClickListener(btnListener); + findViewById(R.id.buttonShowCircleButCropAsSquare).setOnClickListener(btnListener); mRootLayout = (RelativeLayout) findViewById(R.id.layout_root); } diff --git a/simplecropview-sample/src/main/res/layout/activity_main.xml b/simplecropview-sample/src/main/res/layout/activity_main.xml index 50008c7..5ed79b3 100644 --- a/simplecropview-sample/src/main/res/layout/activity_main.xml +++ b/simplecropview-sample/src/main/res/layout/activity_main.xml @@ -158,6 +158,17 @@ android:layout_width="wrap_content" android:layout_height="@dimen/button_height"/> +