Skip to content

Commit

Permalink
Extracted overlay functionality into OverlayView.java.
Browse files Browse the repository at this point in the history
Now UCropView.java is the main GroupView that holds both Crop ImageView and Overlay view.
  • Loading branch information
shliama committed Jan 25, 2016
1 parent a2b6bfa commit d365c7e
Show file tree
Hide file tree
Showing 11 changed files with 345 additions and 168 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0-alpha5'
classpath 'com.android.tools.build:gradle:2.0.0-alpha7'

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
Expand Down
4 changes: 3 additions & 1 deletion ucrop/src/main/java/com/yalantis/ucrop/UCropActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.yalantis.ucrop.view.CropImageView;
import com.yalantis.ucrop.view.GestureCropImageView;
import com.yalantis.ucrop.view.TransformImageView;
import com.yalantis.ucrop.view.UCropView;
import com.yalantis.ucrop.view.widget.AspectRatioTextView;
import com.yalantis.ucrop.view.widget.HorizontalProgressWheelView;

Expand Down Expand Up @@ -165,7 +166,8 @@ private void setupViews() {
}
setStatusBarColor(getResources().getColor(R.color.ucrop_color_statusbar));

mGestureCropImageView = (GestureCropImageView) findViewById(R.id.image_view_crop);
UCropView uCropView = (UCropView) findViewById(R.id.ucrop);
mGestureCropImageView = uCropView.getCropImageView();
mGestureCropImageView.setTransformImageListener(new TransformImageView.TransformImageListener() {
@Override
public void onRotate(float currentAngle) {
Expand Down
175 changes: 30 additions & 145 deletions ucrop/src/main/java/com/yalantis/ucrop/view/CropImageView.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.support.annotation.IntRange;
Expand All @@ -30,34 +28,35 @@ public abstract class CropImageView extends TransformImageView {

public static final float SOURCE_IMAGE_ASPECT_RATIO = 0f;

private static final boolean DEFAULT_SHOW_CROP_FRAME = false;
private static final boolean DEFAULT_SHOW_CROP_GRID = true;
private static final int DEFAULT_CROP_GRID_ROW_COUNT = 3;
private static final int DEFAULT_CROP_GRID_COLUMN_COUNT = 3;
private static final int DEFAULT_IMAGE_TO_CROP_BOUNDS_ANIM_DURATION = 777;

private static final float DEFAULT_ASPECT_RATIO = SOURCE_IMAGE_ASPECT_RATIO;

private static final float DEFAULT_MAX_SCALE_MULTIPLIER = 10.0f;

private final RectF mCropRect = new RectF();
private final RectF mCropViewRect = new RectF();

private final Matrix mTempMatrix = new Matrix();

private int mCropGridRowCount, mCropGridColumnCount;
private float mTargetAspectRatio;
private float[] mGridPoints = null;
private boolean mShowCropFrame, mShowCropGrid;
private Paint mDimmedPaint, mGridInnerLinePaint, mGridOuterLinePaint;
private float mMaxScaleMultiplier;

private CropBoundsChangeListener mCropBoundsChangeListener;

private Runnable mWrapCropBoundsRunnable, mZoomImageToPositionRunnable = null;

private float mMaxScale, mMinScale;
private int mMaxResultImageSizeX = 0, mMaxResultImageSizeY = 0;
private long mImageToWrapCropBoundsAnimDuration = DEFAULT_IMAGE_TO_CROP_BOUNDS_ANIM_DURATION;


/**
* Interface for crop bound change notifying.
*/
public interface CropBoundsChangeListener {

void onCropBoundsChangedRotate(float cropRatio);

}

public CropImageView(Context context) {
this(context, null);
}
Expand All @@ -68,7 +67,6 @@ public CropImageView(Context context, AttributeSet attrs) {

public CropImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}

/**
Expand Down Expand Up @@ -178,11 +176,18 @@ public void setTargetAspectRatio(float targetAspectRatio) {
}

setupCropBounds();
mGridPoints = null;

postInvalidate();
}

@Nullable
public CropBoundsChangeListener getCropBoundsChangeListener() {
return mCropBoundsChangeListener;
}

public void setCropBoundsChangeListener(@Nullable CropBoundsChangeListener cropBoundsChangeListener) {
mCropBoundsChangeListener = cropBoundsChangeListener;
}

/**
* This method sets maximum width for resulting cropped image
*
Expand Down Expand Up @@ -338,81 +343,6 @@ public void setImageToWrapCropBounds(boolean animate) {
}
}

protected void init(Context context, AttributeSet attrs, int defStyle) {
super.init(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ucrop_CropImageView);
processStyledAttributes(a);
a.recycle();
}

/**
* Along with image there are dimmed layer, crop bounds and crop guidelines that must be drawn.
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawDimmedLayer(canvas);
drawCropGrid(canvas);
}

/**
* Could use
* <p/>
* canvas.save();
* canvas.clipRect(mCropViewRect, Region.Op.DIFFERENCE);
* canvas.drawColor(mOverlayColor);
* canvas.restore();
* <p/>
* but this won't properly work on number of devices with HW acceleration enabled.
* So lets just draw rectangles...
*
* @param canvas - current canvas
*/
protected void drawDimmedLayer(@NonNull Canvas canvas) {
canvas.drawRect(0, mCropViewRect.top, mCropViewRect.left, mCropViewRect.bottom, mDimmedPaint);
canvas.drawRect(0, 0, canvas.getWidth(), mCropViewRect.top, mDimmedPaint);
canvas.drawRect(mCropViewRect.right, mCropViewRect.top, canvas.getWidth(), mCropViewRect.bottom, mDimmedPaint);
canvas.drawRect(0, mCropViewRect.bottom, canvas.getWidth(), canvas.getHeight(), mDimmedPaint);
}

/**
* This method draws crop bounds (empty rectangle)
* and crop guidelines (vertical and horizontal lines inside the crop bounds) if needed.
*
* @param canvas - valid canvas object
*/
protected void drawCropGrid(@NonNull Canvas canvas) {
if (mShowCropGrid) {
if (mGridPoints == null && !mCropViewRect.isEmpty()) {

mGridPoints = new float[(mCropGridRowCount - 1) * 4 + (mCropGridColumnCount - 1) * 4];

int index = 0;
for (int i = 0; i < mCropGridRowCount - 1; i++) {
mGridPoints[index++] = mCropViewRect.left;
mGridPoints[index++] = (mCropViewRect.height() * (((float) i + 1.0f) / (float) mCropGridRowCount)) + mCropViewRect.top;
mGridPoints[index++] = mCropViewRect.right;
mGridPoints[index++] = (mCropViewRect.height() * (((float) i + 1.0f) / (float) mCropGridRowCount)) + mCropViewRect.top;
}

for (int i = 0; i < mCropGridColumnCount - 1; i++) {
mGridPoints[index++] = (mCropViewRect.width() * (((float) i + 1.0f) / (float) mCropGridColumnCount)) + mCropViewRect.left;
mGridPoints[index++] = mCropViewRect.top;
mGridPoints[index++] = (mCropViewRect.width() * (((float) i + 1.0f) / (float) mCropGridColumnCount)) + mCropViewRect.left;
mGridPoints[index++] = mCropViewRect.bottom;
}
}

if (mGridPoints != null) {
canvas.drawLines(mGridPoints, mGridInnerLinePaint);
}
}

if (mShowCropFrame) {
canvas.drawRect(mCropViewRect, mGridOuterLinePaint);
}
}

/**
* When image is laid out it must be centered properly to fit current crop bounds.
*/
Expand Down Expand Up @@ -518,81 +448,36 @@ private void setupInitialImagePosition(float drawableWidth, float drawableHeight
* Those are used to configure the view.
*/
@SuppressWarnings("deprecation")
private void processStyledAttributes(@NonNull TypedArray a) {
float targetAspectRatioX = Math.abs(a.getFloat(R.styleable.ucrop_CropImageView_ucrop_aspect_ratio_x, DEFAULT_ASPECT_RATIO));
float targetAspectRatioY = Math.abs(a.getFloat(R.styleable.ucrop_CropImageView_ucrop_aspect_ratio_y, DEFAULT_ASPECT_RATIO));
protected void processStyledAttributes(@NonNull TypedArray a) {
float targetAspectRatioX = Math.abs(a.getFloat(R.styleable.ucrop_UCropView_ucrop_aspect_ratio_x, DEFAULT_ASPECT_RATIO));
float targetAspectRatioY = Math.abs(a.getFloat(R.styleable.ucrop_UCropView_ucrop_aspect_ratio_y, DEFAULT_ASPECT_RATIO));

if (targetAspectRatioX == SOURCE_IMAGE_ASPECT_RATIO || targetAspectRatioY == SOURCE_IMAGE_ASPECT_RATIO) {
mTargetAspectRatio = SOURCE_IMAGE_ASPECT_RATIO;
} else {
mTargetAspectRatio = targetAspectRatioX / targetAspectRatioY;
}

mMaxScaleMultiplier = a.getFloat(R.styleable.ucrop_CropImageView_ucrop_max_scale_multiplier, DEFAULT_MAX_SCALE_MULTIPLIER);

int overlayColor = a.getColor(R.styleable.ucrop_CropImageView_ucrop_overlay_color,
getResources().getColor(R.color.ucrop_color_default_overlay));
mDimmedPaint = new Paint();
mDimmedPaint.setColor(overlayColor);
mDimmedPaint.setStyle(Paint.Style.FILL);

initCropFrameStyle(a);
mShowCropFrame = a.getBoolean(R.styleable.ucrop_CropImageView_ucrop_show_frame, DEFAULT_SHOW_CROP_FRAME);

initCropGridStyle(a);
mShowCropGrid = a.getBoolean(R.styleable.ucrop_CropImageView_ucrop_show_grid, DEFAULT_SHOW_CROP_GRID);
}

/**
* This method setups Paint object for the crop bounds.
*/
@SuppressWarnings("deprecation")
private void initCropFrameStyle(@NonNull TypedArray a) {
int cropFrameStrokeSize = a.getDimensionPixelSize(R.styleable.ucrop_CropImageView_ucrop_frame_stroke_size,
getResources().getDimensionPixelSize(R.dimen.ucrop_default_crop_frame_stoke_size));
int cropFrameColor = a.getColor(R.styleable.ucrop_CropImageView_ucrop_frame_color,
getResources().getColor(R.color.ucrop_color_default_crop_frame));
mGridOuterLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mGridOuterLinePaint.setStrokeWidth(cropFrameStrokeSize);
mGridOuterLinePaint.setColor(cropFrameColor);
mGridOuterLinePaint.setStyle(Paint.Style.STROKE);
}

/**
* This method setups Paint object for the crop guidelines.
*/
@SuppressWarnings("deprecation")
private void initCropGridStyle(@NonNull TypedArray a) {
int cropGridStrokeSize = a.getDimensionPixelSize(R.styleable.ucrop_CropImageView_ucrop_grid_stroke_size,
getResources().getDimensionPixelSize(R.dimen.ucrop_default_crop_grid_stoke_size));
int cropGridColor = a.getColor(R.styleable.ucrop_CropImageView_ucrop_grid_color,
getResources().getColor(R.color.ucrop_color_default_crop_grid));
mGridInnerLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mGridInnerLinePaint.setStrokeWidth(cropGridStrokeSize);
mGridInnerLinePaint.setColor(cropGridColor);

mCropGridRowCount = a.getInt(R.styleable.ucrop_CropImageView_ucrop_grid_row_count, DEFAULT_CROP_GRID_ROW_COUNT);
mCropGridColumnCount = a.getInt(R.styleable.ucrop_CropImageView_ucrop_grid_column_count, DEFAULT_CROP_GRID_COLUMN_COUNT);
mMaxScaleMultiplier = a.getFloat(R.styleable.ucrop_UCropView_ucrop_max_scale_multiplier, DEFAULT_MAX_SCALE_MULTIPLIER);
}

/**
* This method setups crop bounds rectangles for given aspect ratio and view size.
* {@link #mCropViewRect} is used to draw crop bounds - uses padding.
* {@link #mCropRect} is used for crop calculations - doesn't use padding.
* {@link #mCropRect} is used for crop calculations.
*/
private void setupCropBounds() {
int height = (int) (mThisWidth / mTargetAspectRatio);
if (height > mThisHeight) {
int width = (int) (mThisHeight * mTargetAspectRatio);
int halfDiff = (mThisWidth - width) / 2;
mCropRect.set(halfDiff, 0, width + halfDiff, mThisHeight);
mCropViewRect.set(getPaddingLeft() + halfDiff, getPaddingTop(),
getPaddingLeft() + width + halfDiff, getPaddingTop() + mThisHeight);
} else {
int halfDiff = (mThisHeight - height) / 2;
mCropRect.set(0, halfDiff, mThisWidth, height + halfDiff);
mCropViewRect.set(getPaddingLeft(), getPaddingTop() + halfDiff,
getPaddingLeft() + mThisWidth, getPaddingTop() + height + halfDiff);
}

if (mCropBoundsChangeListener != null) {
mCropBoundsChangeListener.onCropBoundsChangedRotate(mTargetAspectRatio);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ public boolean onTouchEvent(MotionEvent event) {
}

@Override
protected void init(Context context, AttributeSet attrs, int defStyle) {
super.init(context, attrs, defStyle);
protected void init() {
super.init();
setupGestureListeners();
}

Expand Down
Loading

0 comments on commit d365c7e

Please sign in to comment.