PictureSelector 裁剪框添加文字提示(笔记)

引言:在不引入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




    

    
    
    


字体颜色自己扩展吧、懒得写方法了;

至此over!

你可能感兴趣的:(PictureSelec,修改,android,PictureSelect,裁剪框文字)