引言:在不引入PictureSelector module的情况下、进行修改。讲人话 就是PictureSelect采用的是implementation xxx.xxxx.xxx 引入方式、在此基础之上进行扩展修改、且不影响其他功能。
注意:PictureSelector 版本<3.0
先看图(符合预期了再往下看):
实现步骤:
一、继承修改OverlayView、重写其onDraw方法(目的就是drawText);
二、复制ucrop_view.xml文件到自己工程的layout中、在ucrop_view.xml中将OverlayView 替换成自己的(ucrop_view.xml 可以在pictureselect库中找到);
原理(不想看可以跳过 手动狗头):
找到裁剪框的Rect、在其顶部和底部drawText、就O了、其中矩形关键字mCropViewRect(RectF);
分析、找到onDraw() 、进入drawDimmedLayer()函数、其中drawDimmedLayer()就是用来画矩形的(就是那个可以拖动的框框)、找到mCropViewRect、在后面DrawText就行了!
具体参考OverlayViewWithText 源码。
如何使用?:
//设置裁剪框上下的文字
OverlayViewWithText.setPictureUCropText("顶部巴拉巴拉", "底部巴拉巴拉")
//设置裁剪框文字距离裁剪框的间距(包含上下文字)
OverlayViewWithText.setPictureUCropMargin(10.dp2Px().toFloat())
//设置裁剪框文字大小
OverlayViewWithText.setPictureUCropTextSize(15f.sp2Px(), 18f.sp2Px())
1、OverlayViewWithText 相关代码在下面:
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.OvershootInterpolator;
import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import com.yalantis.ucrop.R;
import com.yalantis.ucrop.callback.OverlayViewChangeListener;
import com.yalantis.ucrop.util.RectUtils;
import com.yalantis.ucrop.view.OverlayView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Created by Oleksii Shliama (https://github.com/shliama).
*
* This view is used for drawing the overlay on top of the image. It may have frame, crop guidelines and dimmed area.
* This must have LAYER_TYPE_SOFTWARE to draw itself properly.
*/
public class OverlayViewWithText extends OverlayView {
public static final int FREESTYLE_CROP_MODE_DISABLE = 0;
public static final int FREESTYLE_CROP_MODE_ENABLE = 1;
public static final int FREESTYLE_CROP_MODE_ENABLE_WITH_PASS_THROUGH = 2;
public static final boolean DEFAULT_DRAG_FRAME = true;
public static final boolean DEFAULT_SHOW_CROP_FRAME = true;
public static final boolean DEFAULT_SHOW_CROP_GRID = true;
public static final boolean DEFAULT_CIRCLE_DIMMED_LAYER = false;
public static final int DEFAULT_FREESTYLE_CROP_MODE = FREESTYLE_CROP_MODE_DISABLE;
public static final int DEFAULT_CROP_GRID_ROW_COUNT = 2;
public static final int DEFAULT_CROP_GRID_COLUMN_COUNT = 2;
private Paint topTvPaint;
private Paint bomTvPaint;
private static String topCon = "";
private static String bomCon = "";
private float topTvWidth;
private float bomTvWidth;
private int bomTvHeight;
private static float tvMargin;
private static float topTvMargin;
private static float bomTvMargin;
private static float topTvSize;
private static float bomTvSize;
private final RectF mCropViewRect = new RectF();
private final RectF mTempRect = new RectF();
protected int mThisWidth, mThisHeight;
protected float[] mCropGridCorners;
protected float[] mCropGridCenter;
private int mCropGridRowCount, mCropGridColumnCount;
private float mTargetAspectRatio;
private float[] mGridPoints = null;
private boolean mShowCropFrame, mShowCropGrid;
private boolean mCircleDimmedLayer;
private int mDimmedColor;
private int mDimmedBorderColor;
private Path mCircularPath = new Path();
private Paint mDimmedStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint mCropGridPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint mCropFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint mCropFrameCornersPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@FreestyleMode
private int mFreestyleCropMode = DEFAULT_FREESTYLE_CROP_MODE;
private float mPreviousTouchX = -1, mPreviousTouchY = -1;
private int mCurrentTouchCornerIndex = -1;
private int mTouchPointThreshold;
private int mCropRectMinSize;
private int mCropRectCornerTouchAreaLineLength;
private int mStrokeWidth = 1;
private boolean mIsDragFrame = DEFAULT_DRAG_FRAME;
private ValueAnimator smoothAnimator;
private OverlayViewChangeListener mCallback;
private boolean mShouldSetupCropBounds;
{
mTouchPointThreshold = getResources().getDimensionPixelSize(R.dimen.ucrop_default_crop_rect_corner_touch_threshold);
mCropRectMinSize = getResources().getDimensionPixelSize(R.dimen.ucrop_default_crop_rect_min_size);
mCropRectCornerTouchAreaLineLength = getResources().getDimensionPixelSize(R.dimen.ucrop_default_crop_rect_corner_touch_area_line_length);
}
public OverlayViewWithText(Context context) {
this(context, null);
}
public OverlayViewWithText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public OverlayViewWithText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
topTvPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//默认字体大小
if (topTvSize <= 0) topTvSize = 50f;
if (bomTvSize <= 0) bomTvSize = 50f;
topTvPaint.setTextSize(topTvSize);
topTvPaint.setColor(Color.RED);
bomTvPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bomTvPaint.setTextSize(bomTvSize);
bomTvPaint.setColor(Color.RED);
topTvWidth = topTvPaint.measureText(topCon);
bomTvWidth = bomTvPaint.measureText(bomCon);
Rect bounds = new Rect();
bomTvPaint.getTextBounds(bomCon, 0, bomCon.length(), bounds);
bomTvHeight = bounds.height();
Log.d("over_text", "topw bomw" + topTvWidth + "-" + bomTvWidth + " bomTvHeight " + bomTvHeight);
init();
}
public OverlayViewChangeListener getOverlayViewChangeListener() {
return mCallback;
}
public void setOverlayViewChangeListener(OverlayViewChangeListener callback) {
mCallback = callback;
}
@NonNull
public RectF getCropViewRect() {
return mCropViewRect;
}
@Deprecated
/***
* Please use the new method {@link #getFreestyleCropMode() getFreestyleCropMode} method as we have more than 1 freestyle crop mode.
*/
public boolean isFreestyleCropEnabled() {
return mFreestyleCropMode == FREESTYLE_CROP_MODE_ENABLE;
}
//设置裁剪框上下文本间距
public static void setPictureUCropText(String textTop, String textBom) {
topCon = textTop;
bomCon = textBom;
}
//设置文字顶部底部margin
public static void setPictureUCropMargin(float margin) {
tvMargin = margin;
}
//设置文字顶部margin
public static void setPictureUCropTopMargin(float margin) {
topTvMargin = margin;
}
//设置文字底部margin
public static void setPictureUCropBomMargin(float margin) {
bomTvMargin = margin;
}
//设置裁剪字体大小
public static void setPictureUCropTextSize(float topTextSize, float bomTextSize) {
topTvSize = topTextSize;
bomTvSize = bomTextSize;
}
/**
* 重置裁剪文案
* bomCon topCon 是否为空字符串、决定了是否绘制裁剪框文案;
*/
public static void reSetUCropText() {
topCon = "";
bomCon = "";
topTvSize = 0f;
bomTvSize = 0f;
tvMargin = 0;
topTvMargin = 0;
bomTvMargin = 0;
}
@Deprecated
/***
* Please use the new method {@link #setFreestyleCropMode setFreestyleCropMode} method as we have more than 1 freestyle crop mode.
*/
public void setFreestyleCropEnabled(boolean freestyleCropEnabled) {
mFreestyleCropMode = freestyleCropEnabled ? FREESTYLE_CROP_MODE_ENABLE : FREESTYLE_CROP_MODE_DISABLE;
}
public boolean isDragFrame() {
return mIsDragFrame;
}
public void setDragFrame(boolean mIsDragFrame) {
this.mIsDragFrame = mIsDragFrame;
}
/**
* Setter for {@link #mDimmedColor} variable.
*
* @param strokeWidth
*/
public void setDimmedStrokeWidth(int strokeWidth) {
mStrokeWidth = strokeWidth;
if (mDimmedStrokePaint != null) {
mDimmedStrokePaint.setStrokeWidth(mStrokeWidth);
}
}
@FreestyleMode
public int getFreestyleCropMode() {
return mFreestyleCropMode;
}
public void setFreestyleCropMode(@FreestyleMode int mFreestyleCropMode) {
this.mFreestyleCropMode = mFreestyleCropMode;
postInvalidate();
}
/**
* Setter for {@link #mCircleDimmedLayer} variable.
*
* @param circleDimmedLayer - set it to true if you want dimmed layer to be an circle
*/
public void setCircleDimmedLayer(boolean circleDimmedLayer) {
mCircleDimmedLayer = circleDimmedLayer;
}
/**
* Setter for crop grid rows count.
* Resets {@link #mGridPoints} variable because it is not valid anymore.
*/
public void setCropGridRowCount(@IntRange(from = 0) int cropGridRowCount) {
mCropGridRowCount = cropGridRowCount;
mGridPoints = null;
}
/**
* Setter for crop grid columns count.
* Resets {@link #mGridPoints} variable because it is not valid anymore.
*/
public void setCropGridColumnCount(@IntRange(from = 0) int cropGridColumnCount) {
mCropGridColumnCount = cropGridColumnCount;
mGridPoints = null;
}
/**
* Setter for {@link #mShowCropFrame} variable.
*
* @param showCropFrame - set to true if you want to see a crop frame rectangle on top of an image
*/
public void setShowCropFrame(boolean showCropFrame) {
mShowCropFrame = showCropFrame;
}
/**
* Setter for {@link #mShowCropGrid} variable.
*
* @param showCropGrid - set to true if you want to see a crop grid on top of an image
*/
public void setShowCropGrid(boolean showCropGrid) {
mShowCropGrid = showCropGrid;
}
/**
* Setter for {@link #mDimmedColor} variable.
*
* @param dimmedColor - desired color of dimmed area around the crop bounds
*/
public void setDimmedColor(@ColorInt int dimmedColor) {
mDimmedColor = dimmedColor;
}
/**
* Setter for crop frame stroke width
*/
public void setCropFrameStrokeWidth(@IntRange(from = 0) int width) {
mCropFramePaint.setStrokeWidth(width);
}
/**
* Setter for crop grid stroke width
*/
public void setCropGridStrokeWidth(@IntRange(from = 0) int width) {
mCropGridPaint.setStrokeWidth(width);
}
/**
* Setter for {@link #mDimmedColor} variable.
*
* @param dimmedBorderColor - desired color of dimmed area around the crop bounds
*/
public void setDimmedBorderColor(@ColorInt int dimmedBorderColor) {
mDimmedBorderColor = dimmedBorderColor;
if (mDimmedStrokePaint != null) {
mDimmedStrokePaint.setColor(mDimmedBorderColor);
}
}
/**
* Setter for crop frame color
*/
public void setCropFrameColor(@ColorInt int color) {
mCropFramePaint.setColor(color);
}
/**
* Setter for crop grid color
*/
public void setCropGridColor(@ColorInt int color) {
mCropGridPaint.setColor(color);
}
/**
* This method sets aspect ratio for crop bounds.
*
* @param targetAspectRatio - aspect ratio for image crop (e.g. 1.77(7) for 16:9)
*/
public void setTargetAspectRatio(final float targetAspectRatio) {
mTargetAspectRatio = targetAspectRatio;
if (mThisWidth > 0) {
setupCropBounds();
postInvalidate();
} else {
mShouldSetupCropBounds = true;
}
}
/**
* This method setups crop bounds rectangles for given aspect ratio and view size.
* {@link #mCropViewRect} is used to draw crop bounds - uses padding.
*/
public void setupCropBounds() {
int height = (int) (mThisWidth / mTargetAspectRatio);
if (height > mThisHeight) {
int width = (int) (mThisHeight * mTargetAspectRatio);
int halfDiff = (mThisWidth - width) / 2;
mCropViewRect.set(getPaddingLeft() + halfDiff, getPaddingTop(),
getPaddingLeft() + width + halfDiff, getPaddingTop() + mThisHeight);
} else {
int halfDiff = (mThisHeight - height) / 2;
mCropViewRect.set(getPaddingLeft(), getPaddingTop() + halfDiff,
getPaddingLeft() + mThisWidth, getPaddingTop() + height + halfDiff);
}
if (mCallback != null) {
mCallback.onCropRectUpdated(mCropViewRect);
}
updateGridPoints();
}
private void updateGridPoints() {
mCropGridCorners = RectUtils.getCornersFromRect(mCropViewRect);
mCropGridCenter = RectUtils.getCenterFromRect(mCropViewRect);
mGridPoints = null;
mCircularPath.reset();
mCircularPath.addCircle(mCropViewRect.centerX(), mCropViewRect.centerY(),
Math.min(mCropViewRect.width(), mCropViewRect.height()) / 2.f, Path.Direction.CW);
}
protected void init() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
left = getPaddingLeft();
top = getPaddingTop();
right = getWidth() - getPaddingRight();
bottom = getHeight() - getPaddingBottom();
mThisWidth = right - left;
mThisHeight = bottom - top;
if (mShouldSetupCropBounds) {
mShouldSetupCropBounds = false;
setTargetAspectRatio(mTargetAspectRatio);
}
}
}
/**
* 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);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mCropViewRect.isEmpty() || mFreestyleCropMode == FREESTYLE_CROP_MODE_DISABLE) {
return false;
}
float x = event.getX();
float y = event.getY();
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
if (smoothAnimator != null) {
smoothAnimator.cancel();
}
mCurrentTouchCornerIndex = getCurrentTouchIndex(x, y);
boolean shouldHandle = mCurrentTouchCornerIndex != -1 && mCurrentTouchCornerIndex != 4;
if (!shouldHandle) {
mPreviousTouchX = -1;
mPreviousTouchY = -1;
} else if (mPreviousTouchX < 0) {
mPreviousTouchX = x;
mPreviousTouchY = y;
}
return shouldHandle;
}
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_MOVE) {
if (event.getPointerCount() == 1 && mCurrentTouchCornerIndex != -1) {
x = Math.min(Math.max(x, getPaddingLeft()), getWidth() - getPaddingRight());
y = Math.min(Math.max(y, getPaddingTop()), getHeight() - getPaddingBottom());
updateCropViewRect(x, y);
mPreviousTouchX = x;
mPreviousTouchY = y;
return true;
}
}
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
mPreviousTouchX = -1;
mPreviousTouchY = -1;
mCurrentTouchCornerIndex = -1;
if (mCallback != null) {
mCallback.onCropRectUpdated(mCropViewRect);
}
smoothToCenter();
}
return false;
}
/**
* * The order of the corners is:
* 0------->1
* ^ |
* | 4 |
* | v
* 3<-------2
*/
private void updateCropViewRect(float touchX, float touchY) {
mTempRect.set(mCropViewRect);
switch (mCurrentTouchCornerIndex) {
// resize rectangle
case 0:
// 是否可拖动裁剪框
if (isDragFrame()) {
mTempRect.set(touchX, touchY, mCropViewRect.right, mCropViewRect.bottom);
}
break;
case 1:
// 是否可拖动裁剪框
if (isDragFrame()) {
mTempRect.set(mCropViewRect.left, touchY, touchX, mCropViewRect.bottom);
}
break;
case 2:
// 是否可拖动裁剪框
if (isDragFrame()) {
mTempRect.set(mCropViewRect.left, mCropViewRect.top, touchX, touchY);
}
break;
case 3:
// 是否可拖动裁剪框
if (isDragFrame()) {
mTempRect.set(touchX, mCropViewRect.top, mCropViewRect.right, touchY);
}
break;
// move rectangle
case 4:
mTempRect.offset(touchX - mPreviousTouchX, touchY - mPreviousTouchY);
if (mTempRect.left > getLeft() && mTempRect.top > getTop()
&& mTempRect.right < getRight() && mTempRect.bottom < getBottom()) {
mCropViewRect.set(mTempRect);
updateGridPoints();
postInvalidate();
}
return;
}
boolean changeHeight = mTempRect.height() >= mCropRectMinSize;
boolean changeWidth = mTempRect.width() >= mCropRectMinSize;
mCropViewRect.set(
changeWidth ? mTempRect.left : mCropViewRect.left,
changeHeight ? mTempRect.top : mCropViewRect.top,
changeWidth ? mTempRect.right : mCropViewRect.right,
changeHeight ? mTempRect.bottom : mCropViewRect.bottom);
if (changeHeight || changeWidth) {
updateGridPoints();
postInvalidate();
}
}
/**
* * The order of the corners in the float array is:
* 0------->1
* ^ |
* | 4 |
* | v
* 3<-------2
*
* @return - index of corner that is being dragged
*/
private int getCurrentTouchIndex(float touchX, float touchY) {
int closestPointIndex = -1;
double closestPointDistance = mTouchPointThreshold;
for (int i = 0; i < 8; i += 2) {
double distanceToCorner = Math.sqrt(Math.pow(touchX - mCropGridCorners[i], 2)
+ Math.pow(touchY - mCropGridCorners[i + 1], 2));
if (distanceToCorner < closestPointDistance) {
closestPointDistance = distanceToCorner;
closestPointIndex = i / 2;
}
}
if (mFreestyleCropMode == FREESTYLE_CROP_MODE_ENABLE && closestPointIndex < 0 && mCropViewRect.contains(touchX, touchY)) {
return 4;
}
// for (int i = 0; i <= 8; i += 2) {
//
// double distanceToCorner;
// if (i < 8) { // corners
// distanceToCorner = Math.sqrt(Math.pow(touchX - mCropGridCorners[i], 2)
// + Math.pow(touchY - mCropGridCorners[i + 1], 2));
// } else { // center
// distanceToCorner = Math.sqrt(Math.pow(touchX - mCropGridCenter[0], 2)
// + Math.pow(touchY - mCropGridCenter[1], 2));
// }
// if (distanceToCorner < closestPointDistance) {
// closestPointDistance = distanceToCorner;
// closestPointIndex = i / 2;
// }
// }
return closestPointIndex;
}
/**
* This method draws dimmed area around the crop bounds.
*
* @param canvas - valid canvas object
*/
protected void drawDimmedLayer(@NonNull Canvas canvas) {
canvas.save();
if (mCircleDimmedLayer) {
canvas.clipPath(mCircularPath, Region.Op.DIFFERENCE);
} else {
canvas.clipRect(mCropViewRect, Region.Op.DIFFERENCE);
}
canvas.drawColor(mDimmedColor);
canvas.restore();
if (mCircleDimmedLayer) { // Draw 1px stroke to fix antialias
canvas.drawCircle(mCropViewRect.centerX(), mCropViewRect.centerY(),
Math.min(mCropViewRect.width(), mCropViewRect.height()) / 2.f, mDimmedStrokePaint);
}
if (!topCon.equals("")) {
//drawTopText
float centerx = mCropViewRect.centerX() - topTvWidth / 2;
float tmargin;
if (topTvMargin != 0) tmargin = topTvMargin;
else tmargin = tvMargin;
canvas.drawText(topCon, centerx, mCropViewRect.top - tmargin, topTvPaint);
Log.d("over_text ", "draw text " + mCropViewRect + " tmargin " + tmargin);
}
if (!bomCon.equals("")) {
//drawbomTexg
float bomCenterx = mCropViewRect.centerX() - bomTvWidth / 2;
float bmargin;
if (bomTvMargin != 0) bmargin = bomTvMargin;
else bmargin = tvMargin;
canvas.drawText(bomCon, bomCenterx, mCropViewRect.bottom + bomTvHeight + bmargin, bomTvPaint);
Log.d("over_text ", "draw text " + mCropViewRect + " bmargin " + bmargin);
}
}
/**
* 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) * 4 + (mCropGridColumnCount) * 4];
int index = 0;
for (int i = 0; i < mCropGridRowCount; i++) {
mGridPoints[index++] = mCropViewRect.left;
mGridPoints[index++] = (mCropViewRect.height() * (((float) i + 1.0f) / (float) (mCropGridRowCount + 1))) + mCropViewRect.top;
mGridPoints[index++] = mCropViewRect.right;
mGridPoints[index++] = (mCropViewRect.height() * (((float) i + 1.0f) / (float) (mCropGridRowCount + 1))) + mCropViewRect.top;
}
for (int i = 0; i < mCropGridColumnCount; i++) {
mGridPoints[index++] = (mCropViewRect.width() * (((float) i + 1.0f) / (float) (mCropGridColumnCount + 1))) + mCropViewRect.left;
mGridPoints[index++] = mCropViewRect.top;
mGridPoints[index++] = (mCropViewRect.width() * (((float) i + 1.0f) / (float) (mCropGridColumnCount + 1))) + mCropViewRect.left;
mGridPoints[index++] = mCropViewRect.bottom;
}
}
if (mGridPoints != null) {
canvas.drawLines(mGridPoints, mCropGridPaint);
}
}
if (mShowCropFrame) {
canvas.drawRect(mCropViewRect, mCropFramePaint);
}
if (mFreestyleCropMode != FREESTYLE_CROP_MODE_DISABLE) {
canvas.save();
mTempRect.set(mCropViewRect);
mTempRect.inset(mCropRectCornerTouchAreaLineLength, -mCropRectCornerTouchAreaLineLength);
canvas.clipRect(mTempRect, Region.Op.DIFFERENCE);
mTempRect.set(mCropViewRect);
mTempRect.inset(-mCropRectCornerTouchAreaLineLength, mCropRectCornerTouchAreaLineLength);
canvas.clipRect(mTempRect, Region.Op.DIFFERENCE);
canvas.drawRect(mCropViewRect, mCropFrameCornersPaint);
canvas.restore();
}
}
/**
* This method extracts all needed values from the styled attributes.
* Those are used to configure the view.
*/
@SuppressWarnings("deprecation")
protected void processStyledAttributes(@NonNull TypedArray a) {
mCircleDimmedLayer = a.getBoolean(R.styleable.ucrop_UCropView_ucrop_circle_dimmed_layer, DEFAULT_CIRCLE_DIMMED_LAYER);
mDimmedColor = a.getColor(R.styleable.ucrop_UCropView_ucrop_dimmed_color,
getResources().getColor(R.color.ucrop_color_default_dimmed));
mDimmedStrokePaint.setColor(mDimmedBorderColor);
mDimmedStrokePaint.setStyle(Paint.Style.STROKE);
mDimmedStrokePaint.setStrokeWidth(mStrokeWidth);
initCropFrameStyle(a);
mShowCropFrame = a.getBoolean(R.styleable.ucrop_UCropView_ucrop_show_frame, DEFAULT_SHOW_CROP_FRAME);
initCropGridStyle(a);
mShowCropGrid = a.getBoolean(R.styleable.ucrop_UCropView_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_UCropView_ucrop_frame_stroke_size,
getResources().getDimensionPixelSize(R.dimen.ucrop_default_crop_frame_stoke_width));
int cropFrameColor = a.getColor(R.styleable.ucrop_UCropView_ucrop_frame_color,
getResources().getColor(R.color.ucrop_color_default_crop_frame));
mCropFramePaint.setStrokeWidth(cropFrameStrokeSize);
mCropFramePaint.setColor(cropFrameColor);
mCropFramePaint.setStyle(Paint.Style.STROKE);
mCropFrameCornersPaint.setStrokeWidth(cropFrameStrokeSize * 3);
mCropFrameCornersPaint.setColor(cropFrameColor);
mCropFrameCornersPaint.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_UCropView_ucrop_grid_stroke_size,
getResources().getDimensionPixelSize(R.dimen.ucrop_default_crop_grid_stoke_width));
int cropGridColor = a.getColor(R.styleable.ucrop_UCropView_ucrop_grid_color,
getResources().getColor(R.color.ucrop_color_default_crop_grid));
mCropGridPaint.setStrokeWidth(cropGridStrokeSize);
mCropGridPaint.setColor(cropGridColor);
mCropGridRowCount = a.getInt(R.styleable.ucrop_UCropView_ucrop_grid_row_count, DEFAULT_CROP_GRID_ROW_COUNT);
mCropGridColumnCount = a.getInt(R.styleable.ucrop_UCropView_ucrop_grid_column_count, DEFAULT_CROP_GRID_COLUMN_COUNT);
}
@Retention(RetentionPolicy.SOURCE)
@IntDef({FREESTYLE_CROP_MODE_DISABLE, FREESTYLE_CROP_MODE_ENABLE, FREESTYLE_CROP_MODE_ENABLE_WITH_PASS_THROUGH})
public @interface FreestyleMode {
}
/**
* 平滑移动至中心
*/
private void smoothToCenter() {
Point centerPoint = new Point((getRight() + getLeft()) / 2, (getTop() + getBottom()) / 2);
final int offsetY = (int) (centerPoint.y - mCropViewRect.centerY());
final int offsetX = (int) (centerPoint.x - mCropViewRect.centerX());
final RectF before = new RectF(mCropViewRect);
Log.d("pisa", "pre" + mCropViewRect);
RectF after = new RectF(mCropViewRect);
after.offset(offsetX, offsetY);
Log.d("pisa", "after" + after);
if (smoothAnimator != null) {
smoothAnimator.cancel();
}
smoothAnimator = ValueAnimator.ofFloat(0, 1);
smoothAnimator.setDuration(1000);
smoothAnimator.setInterpolator(new OvershootInterpolator());
smoothAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
float lastAnimationValue = 0f;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float x = offsetX * (float) animation.getAnimatedValue();
float y = offsetY * (float) animation.getAnimatedValue();
mCropViewRect.set(new RectF(
before.left + x,
before.top + y,
before.right + x,
before.bottom + y
));
updateGridPoints();
postInvalidate();
if (mCallback != null) {
mCallback.postTranslate(
offsetX * ((float) animation.getAnimatedValue() - lastAnimationValue),
offsetY * ((float) animation.getAnimatedValue() - lastAnimationValue)
);
}
lastAnimationValue = (float) animation.getAnimatedValue();
}
});
smoothAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (mCallback != null) {
mCallback.onCropRectUpdated(mCropViewRect);
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
smoothAnimator.start();
}
}
2、ucrop_view.xml
字体颜色自己扩展吧、懒得写方法了;