SM-A6060_20200118143230.gif
圆形头像裁剪
package com.yj.myapplication;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.yj.myapplication.view.ClipViewLayout;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
/**
* 头像裁剪Activity
*/
public class ClipImageActivity extends AppCompatActivity implements View.OnClickListener {
private ClipViewLayout clipViewLayout1;
private ImageView back;
private TextView btnCancel;
private TextView btnOk;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clip_image);
initView();
}
/**
* 初始化组件
*/
public void initView() {
clipViewLayout1 = (ClipViewLayout) findViewById(R.id.clipViewLayout1);
back = (ImageView) findViewById(R.id.iv_back);
btnCancel = (TextView) findViewById(R.id.btn_cancel);
btnOk = (TextView) findViewById(R.id.bt_ok);
//设置点击事件监听器
back.setOnClickListener(this);
btnCancel.setOnClickListener(this);
btnOk.setOnClickListener(this);
}
@Override
protected void onResume() {
super.onResume();
//设置图片资源
clipViewLayout1.setImageSrc(getIntent().getData());
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_back:
finish();
break;
case R.id.btn_cancel:
finish();
break;
case R.id.bt_ok:
generateUriAndReturn();
break;
}
}
/**
* 生成Uri并且通过setResult返回给打开的activity
*/
private void generateUriAndReturn() {
//调用返回剪切图
Bitmap zoomedCropBitmap;
zoomedCropBitmap = clipViewLayout1.clip();
if (zoomedCropBitmap == null) {
Log.e("android", "zoomedCropBitmap == null");
return;
}
Uri mSaveUri = Uri.fromFile(new File(getCacheDir(), "cropped_" + System.currentTimeMillis() + ".jpg"));
if (mSaveUri != null) {
OutputStream outputStream = null;
try {
outputStream = getContentResolver().openOutputStream(mSaveUri);
if (outputStream != null) {
zoomedCropBitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream);
}
} catch (IOException ex) {
Log.e("android", "Cannot open file: " + mSaveUri, ex);
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Intent intent = new Intent();
intent.setData(mSaveUri);
setResult(RESULT_OK, intent);
finish();
}
}
}
自定义view
package com.yj.myapplication.view;
/*
* Copyright 2014 - 2016 Henning Dodenhof
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.widget.ImageView;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import com.yj.myapplication.R;
public class CircleImageView extends ImageView {
private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
private static final int COLORDRAWABLE_DIMENSION = 2;
private static final int DEFAULT_BORDER_WIDTH = 0;
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;
private static final boolean DEFAULT_BORDER_OVERLAY = false;
private final RectF mDrawableRect = new RectF();
private final RectF mBorderRect = new RectF();
private final Matrix mShaderMatrix = new Matrix();
private final Paint mBitmapPaint = new Paint();
private final Paint mBorderPaint = new Paint();
private final Paint mFillPaint = new Paint();
private int mBorderColor = DEFAULT_BORDER_COLOR;
private int mBorderWidth = DEFAULT_BORDER_WIDTH;
private int mFillColor = DEFAULT_FILL_COLOR;
private Bitmap mBitmap;
private BitmapShader mBitmapShader;
private int mBitmapWidth;
private int mBitmapHeight;
private float mDrawableRadius;
private float mBorderRadius;
private ColorFilter mColorFilter;
private boolean mReady;
private boolean mSetupPending;
private boolean mBorderOverlay;
private boolean mDisableCircularTransformation;
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH);
mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);
mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY);
mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR);
a.recycle();
init();
}
private void init() {
super.setScaleType(SCALE_TYPE);
mReady = true;
if (mSetupPending) {
setup();
mSetupPending = false;
}
}
@Override
public ScaleType getScaleType() {
return SCALE_TYPE;
}
@Override
public void setScaleType(ScaleType scaleType) {
if (scaleType != SCALE_TYPE) {
throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
}
}
@Override
public void setAdjustViewBounds(boolean adjustViewBounds) {
if (adjustViewBounds) {
throw new IllegalArgumentException("adjustViewBounds not supported.");
}
}
@Override
protected void onDraw(Canvas canvas) {
if (mDisableCircularTransformation) {
super.onDraw(canvas);
return;
}
if (mBitmap == null) {
return;
}
if (mFillColor != Color.TRANSPARENT) {
canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mFillPaint);
}
canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint);
if (mBorderWidth > 0) {
canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setup();
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
setup();
}
@Override
public void setPaddingRelative(int start, int top, int end, int bottom) {
super.setPaddingRelative(start, top, end, bottom);
setup();
}
public int getBorderColor() {
return mBorderColor;
}
public void setBorderColor(@ColorInt int borderColor) {
if (borderColor == mBorderColor) {
return;
}
mBorderColor = borderColor;
mBorderPaint.setColor(mBorderColor);
invalidate();
}
/**
* @deprecated Use {@link #setBorderColor(int)} instead
*/
@Deprecated
public void setBorderColorResource(@ColorRes int borderColorRes) {
setBorderColor(getContext().getResources().getColor(borderColorRes));
}
/**
* Return the color drawn behind the circle-shaped drawable.
*
* @return The color drawn behind the drawable
*
* @deprecated Fill color support is going to be removed in the future
*/
@Deprecated
public int getFillColor() {
return mFillColor;
}
/**
* Set a color to be drawn behind the circle-shaped drawable. Note that
* this has no effect if the drawable is opaque or no drawable is set.
*
* @param fillColor The color to be drawn behind the drawable
*
* @deprecated Fill color support is going to be removed in the future
*/
@Deprecated
public void setFillColor(@ColorInt int fillColor) {
if (fillColor == mFillColor) {
return;
}
mFillColor = fillColor;
mFillPaint.setColor(fillColor);
invalidate();
}
/**
* Set a color to be drawn behind the circle-shaped drawable. Note that
* this has no effect if the drawable is opaque or no drawable is set.
*
* @param fillColorRes The color resource to be resolved to a color and
* drawn behind the drawable
*
* @deprecated Fill color support is going to be removed in the future
*/
@Deprecated
public void setFillColorResource(@ColorRes int fillColorRes) {
setFillColor(getContext().getResources().getColor(fillColorRes));
}
public int getBorderWidth() {
return mBorderWidth;
}
public void setBorderWidth(int borderWidth) {
if (borderWidth == mBorderWidth) {
return;
}
mBorderWidth = borderWidth;
setup();
}
public boolean isBorderOverlay() {
return mBorderOverlay;
}
public void setBorderOverlay(boolean borderOverlay) {
if (borderOverlay == mBorderOverlay) {
return;
}
mBorderOverlay = borderOverlay;
setup();
}
public boolean isDisableCircularTransformation() {
return mDisableCircularTransformation;
}
public void setDisableCircularTransformation(boolean disableCircularTransformation) {
if (mDisableCircularTransformation == disableCircularTransformation) {
return;
}
mDisableCircularTransformation = disableCircularTransformation;
initializeBitmap();
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
initializeBitmap();
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
initializeBitmap();
}
@Override
public void setImageResource(@DrawableRes int resId) {
super.setImageResource(resId);
initializeBitmap();
}
@Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
initializeBitmap();
}
@Override
public void setColorFilter(ColorFilter cf) {
if (cf == mColorFilter) {
return;
}
mColorFilter = cf;
applyColorFilter();
invalidate();
}
@Override
public ColorFilter getColorFilter() {
return mColorFilter;
}
private void applyColorFilter() {
if (mBitmapPaint != null) {
mBitmapPaint.setColorFilter(mColorFilter);
}
}
private Bitmap getBitmapFromDrawable(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
try {
Bitmap bitmap;
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private void initializeBitmap() {
if (mDisableCircularTransformation) {
mBitmap = null;
} else {
mBitmap = getBitmapFromDrawable(getDrawable());
}
setup();
}
private void setup() {
if (!mReady) {
mSetupPending = true;
return;
}
if (getWidth() == 0 && getHeight() == 0) {
return;
}
if (mBitmap == null) {
invalidate();
return;
}
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setShader(mBitmapShader);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor);
mBorderPaint.setStrokeWidth(mBorderWidth);
mFillPaint.setStyle(Paint.Style.FILL);
mFillPaint.setAntiAlias(true);
mFillPaint.setColor(mFillColor);
mBitmapHeight = mBitmap.getHeight();
mBitmapWidth = mBitmap.getWidth();
mBorderRect.set(calculateBounds());
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
mDrawableRect.set(mBorderRect);
if (!mBorderOverlay && mBorderWidth > 0) {
mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f);
}
mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
applyColorFilter();
updateShaderMatrix();
invalidate();
}
private RectF calculateBounds() {
int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
int sideLength = Math.min(availableWidth, availableHeight);
float left = getPaddingLeft() + (availableWidth - sideLength) / 2f;
float top = getPaddingTop() + (availableHeight - sideLength) / 2f;
return new RectF(left, top, left + sideLength, top + sideLength);
}
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
scale = mDrawableRect.height() / (float) mBitmapHeight;
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mDrawableRect.width() / (float) mBitmapWidth;
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
}
mShaderMatrix.setScale(scale, scale);
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
mBitmapShader.setLocalMatrix(mShaderMatrix);
}
}
头像上传裁剪框
package com.yj.myapplication.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Xfermode;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
/**
* 头像上传裁剪框
*/
public class ClipView extends View {
private Paint paint = new Paint();
//画裁剪区域边框的画笔
private Paint borderPaint = new Paint();
//裁剪框水平方向间距
private float mHorizontalPadding;
//裁剪框边框宽度
private int clipBorderWidth;
//裁剪圆框的半径
private int clipRadiusWidth;
//裁剪框矩形宽度
private int clipWidth;
//裁剪框类别,(圆形、矩形),默认为圆形
private ClipType clipType = ClipType.CIRCLE;
private Xfermode xfermode;
public ClipView(Context context) {
this(context, null);
}
public ClipView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ClipView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//去锯齿
paint.setAntiAlias(true);
borderPaint.setStyle(Style.STROKE);
borderPaint.setColor(Color.WHITE);
borderPaint.setStrokeWidth(clipBorderWidth);
borderPaint.setAntiAlias(true);
xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int LAYER_FLAGS = Canvas.ALL_SAVE_FLAG;
//通过Xfermode的DST_OUT来产生中间的透明裁剪区域,一定要另起一个Layer(层)
canvas.saveLayer(0, 0, this.getWidth(), this.getHeight(), null, LAYER_FLAGS);
//设置背景
canvas.drawColor(Color.parseColor("#a8000000"));
paint.setXfermode(xfermode);
//绘制圆形裁剪框
if (clipType == ClipType.CIRCLE) {
//中间的透明的圆
canvas.drawCircle(this.getWidth() / 2, this.getHeight() / 2, clipRadiusWidth, paint);
//白色的圆边框
canvas.drawCircle(this.getWidth() / 2, this.getHeight() / 2, clipRadiusWidth, borderPaint);
} else if (clipType == ClipType.RECTANGLE) { //绘制矩形裁剪框
//绘制中间的矩形
canvas.drawRect(mHorizontalPadding, this.getHeight() / 2 - clipWidth / 2,
this.getWidth() - mHorizontalPadding, this.getHeight() / 2 + clipWidth / 2, paint);
//绘制白色的矩形边框
canvas.drawRect(mHorizontalPadding, this.getHeight() / 2 - clipWidth / 2,
this.getWidth() - mHorizontalPadding, this.getHeight() / 2 + clipWidth / 2, borderPaint);
}
//出栈,恢复到之前的图层,意味着新建的图层会被删除,新建图层上的内容会被绘制到canvas (or the previous layer)
canvas.restore();
}
/**
* 获取裁剪区域的Rect
*
* @return
*/
public Rect getClipRect() {
Rect rect = new Rect();
//宽度的一半 - 圆的半径
rect.left = (this.getWidth() / 2 - clipRadiusWidth);
//宽度的一半 + 圆的半径
rect.right = (this.getWidth() / 2 + clipRadiusWidth);
//高度的一半 - 圆的半径
rect.top = (this.getHeight() / 2 - clipRadiusWidth);
//高度的一半 + 圆的半径
rect.bottom = (this.getHeight() / 2 + clipRadiusWidth);
return rect;
}
/**
* 设置裁剪框边框宽度
*
* @param clipBorderWidth
*/
public void setClipBorderWidth(int clipBorderWidth) {
this.clipBorderWidth = clipBorderWidth;
borderPaint.setStrokeWidth(clipBorderWidth);
invalidate();
}
/**
* 设置裁剪框水平间距
*
* @param mHorizontalPadding
*/
public void setmHorizontalPadding(float mHorizontalPadding) {
this.mHorizontalPadding = mHorizontalPadding;
this.clipRadiusWidth = (int) (getScreenWidth(getContext()) - 2 * mHorizontalPadding) / 2;
this.clipWidth = clipRadiusWidth * 2;
}
/**
* 获得屏幕高度
*
* @param context
* @return
*/
public static int getScreenWidth(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
/**
* 设置裁剪框类别
*
* @param clipType
*/
public void setClipType(ClipType clipType) {
this.clipType = clipType;
}
/**
* 裁剪框类别,圆形、矩形
*/
public enum ClipType {
CIRCLE, RECTANGLE
}
}
package com.yj.myapplication.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.net.Uri;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.yj.myapplication.R;
import java.io.IOException;
import static com.yj.myapplication.util.FileUtil.getRealFilePathFromUri;
/**
* 头像上传原图裁剪容器
*/
public class ClipViewLayout extends RelativeLayout {
//裁剪原图
private ImageView imageView;
//裁剪框
private ClipView clipView;
//裁剪框水平方向间距,xml布局文件中指定
private float mHorizontalPadding;
//裁剪框垂直方向间距,计算得出
private float mVerticalPadding;
//图片缩放、移动操作矩阵
private Matrix matrix = new Matrix();
//图片原来已经缩放、移动过的操作矩阵
private Matrix savedMatrix = new Matrix();
//动作标志:无
private static final int NONE = 0;
//动作标志:拖动
private static final int DRAG = 1;
//动作标志:缩放
private static final int ZOOM = 2;
//初始化动作标志
private int mode = NONE;
//记录起始坐标
private PointF start = new PointF();
//记录缩放时两指中间点坐标
private PointF mid = new PointF();
private float oldDist = 1f;
//用于存放矩阵的9个值
private final float[] matrixValues = new float[9];
//最小缩放比例
private float minScale;
//最大缩放比例
private float maxScale = 4;
public ClipViewLayout(Context context) {
this(context, null);
}
public ClipViewLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ClipViewLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
//初始化控件自定义的属性
public void init(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ClipViewLayout);
//获取剪切框距离左右的边距, 默认为50dp
mHorizontalPadding = array.getDimensionPixelSize(R.styleable.ClipViewLayout_mHorizontalPadding,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics()));
//获取裁剪框边框宽度,默认1dp
int clipBorderWidth = array.getDimensionPixelSize(R.styleable.ClipViewLayout_clipBorderWidth,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics()));
//裁剪框类型(圆或者矩形)
int clipType = array.getInt(R.styleable.ClipViewLayout_clipType, 1);
//回收
array.recycle();
clipView = new ClipView(context);
//设置裁剪框类型
clipView.setClipType(clipType == 1 ? ClipView.ClipType.CIRCLE : ClipView.ClipType.RECTANGLE);
//设置剪切框边框
clipView.setClipBorderWidth(clipBorderWidth);
//设置剪切框水平间距
clipView.setmHorizontalPadding(mHorizontalPadding);
imageView = new ImageView(context);
//相对布局布局参数
android.view.ViewGroup.LayoutParams lp = new LayoutParams(
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
android.view.ViewGroup.LayoutParams.MATCH_PARENT);
this.addView(imageView, lp);
this.addView(clipView, lp);
}
/**
* 初始化图片
*/
public void setImageSrc(final Uri uri) {
//需要等到imageView绘制完毕再初始化原图
ViewTreeObserver observer = imageView.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
initSrcPic(uri);
imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
}
/**
* 初始化图片
* step 1: decode 出 720*1280 左右的照片 因为原图可能比较大 直接加载出来会OOM
* step 2: 将图片缩放 移动到imageView 中间
*/
public void initSrcPic(Uri uri) {
if (uri == null) {
return;
}
Log.d("evan", "**********clip_view uri******* " + uri);
String path = getRealFilePathFromUri(getContext(), uri);
Log.d("evan", "**********clip_view path******* " + path);
if (TextUtils.isEmpty(path)) {
return;
}
//这里decode出720*1280 左右的照片,防止OOM
Bitmap bitmap = decodeSampledBitmap(path, 720, 1280);
if (bitmap == null) {
return;
}
//竖屏拍照的照片,直接使用的话,会旋转90度,下面代码把角度旋转过来
int rotation = getExifOrientation(path); //查询旋转角度
Matrix m = new Matrix();
m.setRotate(rotation);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
//图片的缩放比
float scale;
if (bitmap.getWidth() >= bitmap.getHeight()) {//宽图
scale = (float) imageView.getWidth() / bitmap.getWidth();
//如果高缩放后小于裁剪区域 则将裁剪区域与高的缩放比作为最终的缩放比
Rect rect = clipView.getClipRect();
//高的最小缩放比
minScale = rect.height() / (float) bitmap.getHeight();
if (scale < minScale) {
scale = minScale;
}
} else {//高图
//高的缩放比
scale = (float) imageView.getHeight() / bitmap.getHeight();
//如果宽缩放后小于裁剪区域 则将裁剪区域与宽的缩放比作为最终的缩放比
Rect rect = clipView.getClipRect();
//宽的最小缩放比
minScale = rect.width() / (float) bitmap.getWidth();
if (scale < minScale) {
scale = minScale;
}
}
// 缩放
matrix.postScale(scale, scale);
// 平移,将缩放后的图片平移到imageview的中心
//imageView的中心x
int midX = imageView.getWidth() / 2;
//imageView的中心y
int midY = imageView.getHeight() / 2;
//bitmap的中心x
int imageMidX = (int) (bitmap.getWidth() * scale / 2);
//bitmap的中心y
int imageMidY = (int) (bitmap.getHeight() * scale / 2);
matrix.postTranslate(midX - imageMidX, midY - imageMidY);
imageView.setScaleType(ImageView.ScaleType.MATRIX);
imageView.setImageMatrix(matrix);
imageView.setImageBitmap(bitmap);
}
/**
* 查询图片旋转角度
*/
public static int getExifOrientation(String filepath) {// YOUR MEDIA PATH AS STRING
int degree = 0;
ExifInterface exif = null;
try {
exif = new ExifInterface(filepath);
} catch (IOException ex) {
ex.printStackTrace();
}
if (exif != null) {
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
if (orientation != -1) {
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
}
}
}
return degree;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
//设置开始点位置
start.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
//开始放下时候两手指间的距离
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) { //拖动
matrix.set(savedMatrix);
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
mVerticalPadding = clipView.getClipRect().top;
matrix.postTranslate(dx, dy);
//检查边界
checkBorder();
} else if (mode == ZOOM) { //缩放
//缩放后两手指间的距离
float newDist = spacing(event);
if (newDist > 10f) {
//手势缩放比例
float scale = newDist / oldDist;
if (scale < 1) { //缩小
if (getScale() > minScale) {
matrix.set(savedMatrix);
mVerticalPadding = clipView.getClipRect().top;
matrix.postScale(scale, scale, mid.x, mid.y);
//缩放到最小范围下面去了,则返回到最小范围大小
while (getScale() < minScale) {
//返回到最小范围的放大比例
scale = 1 + 0.01F;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
//边界检查
checkBorder();
} else { //放大
if (getScale() <= maxScale) {
matrix.set(savedMatrix);
mVerticalPadding = clipView.getClipRect().top;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
}
}
imageView.setImageMatrix(matrix);
break;
}
return true;
}
/**
* 根据当前图片的Matrix获得图片的范围
*/
private RectF getMatrixRectF(Matrix matrix) {
RectF rect = new RectF();
Drawable d = imageView.getDrawable();
if (null != d) {
rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(rect);
}
return rect;
}
/**
* 边界检测
*/
private void checkBorder() {
RectF rect = getMatrixRectF(matrix);
float deltaX = 0;
float deltaY = 0;
int width = imageView.getWidth();
int height = imageView.getHeight();
// 如果宽或高大于屏幕,则控制范围 ; 这里的0.001是因为精度丢失会产生问题,但是误差一般很小,所以我们直接加了一个0.01
if (rect.width() >= width - 2 * mHorizontalPadding) {
if (rect.left > mHorizontalPadding) {
deltaX = -rect.left + mHorizontalPadding;
}
if (rect.right < width - mHorizontalPadding) {
deltaX = width - mHorizontalPadding - rect.right;
}
}
if (rect.height() >= height - 2 * mVerticalPadding) {
if (rect.top > mVerticalPadding) {
deltaY = -rect.top + mVerticalPadding;
}
if (rect.bottom < height - mVerticalPadding) {
deltaY = height - mVerticalPadding - rect.bottom;
}
}
matrix.postTranslate(deltaX, deltaY);
}
/**
* 获得当前的缩放比例
*/
public final float getScale() {
matrix.getValues(matrixValues);
return matrixValues[Matrix.MSCALE_X];
}
/**
* 多点触控时,计算最先放下的两指距离
*/
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
/**
* 多点触控时,计算最先放下的两指中心坐标
*/
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
/**
* 获取剪切图
*/
public Bitmap clip() {
imageView.setDrawingCacheEnabled(true);
imageView.buildDrawingCache();
Rect rect = clipView.getClipRect();
Bitmap cropBitmap = null;
Bitmap zoomedCropBitmap = null;
try {
cropBitmap = Bitmap.createBitmap(imageView.getDrawingCache(), rect.left, rect.top, rect.width(), rect.height());
zoomedCropBitmap = zoomBitmap(cropBitmap, 200, 200);
} catch (Exception e) {
e.printStackTrace();
}
if (cropBitmap != null) {
cropBitmap.recycle();
}
// 释放资源
imageView.destroyDrawingCache();
return zoomedCropBitmap;
}
/**
* 图片等比例压缩
*
* @param filePath
* @param reqWidth 期望的宽
* @param reqHeight 期望的高
* @return
*/
public static Bitmap decodeSampledBitmap(String filePath, int reqWidth,
int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
//bitmap is null
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filePath, options);
}
/**
* 计算InSampleSize
* 宽的压缩比和高的压缩比的较小值 取接近的2的次幂的值
* 比如宽的压缩比是3 高的压缩比是5 取较小值3 而InSampleSize必须是2的次幂,取接近的2的次幂4
*
* @param options
* @param reqWidth
* @param reqHeight
* @return
*/
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
int ratio = heightRatio < widthRatio ? heightRatio : widthRatio;
// inSampleSize只能是2的次幂 将ratio就近取2的次幂的值
if (ratio < 3)
inSampleSize = ratio;
else if (ratio < 6.5)
inSampleSize = 4;
else if (ratio < 8)
inSampleSize = 8;
else
inSampleSize = ratio;
}
return inSampleSize;
}
/**
* 图片缩放到指定宽高
* <p/>
* 非等比例压缩,图片会被拉伸
*
* @param bitmap 源位图对象
* @param w 要缩放的宽度
* @param h 要缩放的高度
* @return 新Bitmap对象
*/
public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Matrix matrix = new Matrix();
float scaleWidth = ((float) w / width);
float scaleHeight = ((float) h / height);
matrix.postScale(scaleWidth, scaleHeight);
Bitmap newBmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
return newBmp;
}
}
防止用户多次点击控件,多次进入界面
package com.yj.base.utils;
public class NoDoubleClickUtils {
private static long lastClickTime;
private final static int SPACE_TIME = 500;
public static void initLastClickTime() {
lastClickTime = 0;
}
public synchronized static boolean isDoubleClick() {
long currentTime = System.currentTimeMillis();
boolean isClick2;
if (currentTime - lastClickTime >
SPACE_TIME) {
isClick2 = false;
} else {
isClick2 = true;
}
lastClickTime = currentTime;
return isClick2;
}
}
文件读取
package com.yj.myapplication.util;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.text.TextUtils;
import java.io.File;
/**
* 文件工具类
*/
public class FileUtil {
/**
* 根据Uri返回文件绝对路径
* 兼容了file:///开头的 和 content://开头的情况
*/
public static String getRealFilePathFromUri(final Context context, final Uri uri) {
if (null == uri) return null;
final String scheme = uri.getScheme();
String data = null;
if (scheme == null) {
data = uri.getPath();
}
else if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(scheme)) {
data = uri.getPath();
} else if (ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(scheme)) {
Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);
if (null != cursor) {
if (cursor.moveToFirst()) {
int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
if (index > -1) {
data = cursor.getString(index);
}
}
cursor.close();
}
}
return data;
}
/**
* 检查文件是否存在
*/
public static String checkDirPath(String dirPath) {
if (TextUtils.isEmpty(dirPath)) {
return "";
}
File dir = new File(dirPath);
if (!dir.exists()) {
dir.mkdirs();
}
return dirPath;
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#173070">
<ImageView
android:id="@+id/iv_back"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:src="@drawable/btn_back_white" />
<TextView
android:id="@+id/stock_name"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:text="移动和缩放"
android:textColor="#ffffff"
android:textSize="20sp" />
</RelativeLayout>
<!--圆形裁剪框示例
app:clipBorderWidth="5dp" : 裁剪框边框宽度
app:clipType="circle" : 裁剪框类型为圆形
app:mHorizontalPadding="30dp" :裁剪框距离左右边距为30dp
-->
<!--矩形裁剪框示例 -->
<com.yj.myapplication.view.ClipViewLayout
android:id="@+id/clipViewLayout1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:clipBorderWidth="2dp"
app:clipType="circle"
app:mHorizontalPadding="30dp" />
<RelativeLayout
android:id="@+id/bottom"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#1C1C1C">
<TextView
android:id="@+id/btn_cancel"
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignTop="@+id/bt_ok"
android:gravity="center_vertical|start"
android:paddingEnd="0dp"
android:paddingLeft="15dp"
android:paddingRight="0dp"
android:paddingStart="15dp"
android:text="取消"
android:textColor="#ffffff"
android:textSize="16sp" />
<TextView
android:id="@+id/bt_ok"
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="center_vertical|end"
android:paddingEnd="15dp"
android:paddingLeft="0dp"
android:paddingRight="15dp"
android:paddingStart="0dp"
android:text="选取"
android:textColor="#ffffff"
android:textSize="16sp" />
</RelativeLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:orientation="vertical">
<TextView
android:id="@+id/btn_photo"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#E8E8E8"
android:gravity="center"
android:text="从相册选择"
android:textColor="#1079FF"
android:textSize="18sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#C9C9CB" />
<TextView
android:id="@+id/btn_cancel"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#E8E8E8"
android:gravity="center"
android:text="取消"
android:textColor="#1079FF"
android:textSize="18sp" />
</LinearLayout>
在values 文件夹下面创建attrs.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--自定义属性 -->
<declare-styleable name="ClipViewLayout">
<attr name="clipType" format="enum">
<enum name="circle" value="1" />
<enum name="rectangle" value="2" />
</attr>
<attr name="mHorizontalPadding" format="dimension" />
<attr name="clipBorderWidth" format="dimension" />
</declare-styleable>
<declare-styleable name="CircleImageView">
<attr name="civ_border_width" format="dimension" />
<attr name="civ_border_color" format="color" />
<attr name="civ_border_overlay" format="boolean" />
<attr name="civ_fill_color" format="color" />
</declare-styleable>
</resources>
在res文件夹下面创建xml包在包里面创建file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path path="image/" name="image" />
</paths>
MainActivity代码
package com.yj.myapplication;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import com.yj.myapplication.util.FileUtil;
import com.yj.myapplication.view.CircleImageView;
import java.io.File;
import static com.yj.myapplication.util.FileUtil.getRealFilePathFromUri;
/**
* 主界面
*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
//请求相机
private static final int REQUEST_CAPTURE = 100;
//请求相册
private static final int REQUEST_PICK = 101;
//请求截图
private static final int REQUEST_CROP_PHOTO = 102;
//请求访问外部存储
private static final int READ_EXTERNAL_STORAGE_REQUEST_CODE = 103;
//请求写入外部存储
private static final int WRITE_EXTERNAL_STORAGE_REQUEST_CODE = 104;
//头像1
private CircleImageView headImage1;
//头像2
private ImageView headImage2;
//调用照相机返回图片文件
private File tempFile;
// 1: qq, 2: weixin
private int type;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
headImage1 = (CircleImageView) findViewById(R.id.head_image1);
headImage2 = (ImageView) findViewById(R.id.head_image2);
RelativeLayout qqLayout = (RelativeLayout) findViewById(R.id.qqLayout);
RelativeLayout weixinLayout = (RelativeLayout) findViewById(R.id.weixinLayout);
qqLayout.setOnClickListener(this);
weixinLayout.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.qqLayout:
type = 1;
uploadHeadImage();
break;
case R.id.weixinLayout:
type = 2;
uploadHeadImage();
break;
}
}
/**
* 上传头像
*/
private void uploadHeadImage() {
View view = LayoutInflater.from(this).inflate(R.layout.layout_popupwindow, null);
TextView btnCarema = (TextView) view.findViewById(R.id.btn_camera);
TextView btnPhoto = (TextView) view.findViewById(R.id.btn_photo);
TextView btnCancel = (TextView) view.findViewById(R.id.btn_cancel);
final PopupWindow popupWindow = new PopupWindow(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setBackgroundDrawable(getResources().getDrawable(android.R.color.transparent));
popupWindow.setOutsideTouchable(true);
View parent = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
popupWindow.showAtLocation(parent, Gravity.BOTTOM, 0, 0);
//popupWindow在弹窗的时候背景半透明
final WindowManager.LayoutParams params = getWindow().getAttributes();
params.alpha = 0.5f;
getWindow().setAttributes(params);
popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
params.alpha = 1.0f;
getWindow().setAttributes(params);
}
});
btnCarema.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//权限判断
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//申请WRITE_EXTERNAL_STORAGE权限
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
WRITE_EXTERNAL_STORAGE_REQUEST_CODE);
} else {
//跳转到调用系统相机
gotoCamera();
}
popupWindow.dismiss();
}
});
btnPhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//权限判断
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//申请READ_EXTERNAL_STORAGE权限
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
READ_EXTERNAL_STORAGE_REQUEST_CODE);
} else {
//跳转到相册
gotoPhoto();
}
popupWindow.dismiss();
}
});
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
popupWindow.dismiss();
}
});
}
/**
* 外部存储权限申请返回
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == WRITE_EXTERNAL_STORAGE_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
gotoCamera();
}
} else if (requestCode == READ_EXTERNAL_STORAGE_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
gotoPhoto();
}
}
}
/**
* 跳转到相册
*/
private void gotoPhoto() {
Log.d("evan", "*****************打开图库********************");
//跳转到调用系统图库
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(Intent.createChooser(intent, "请选择图片"), REQUEST_PICK);
}
/**
* 跳转到照相机
*/
private void gotoCamera() {
Log.d("evan", "*****************打开相机********************");
//创建拍照存储的图片文件
tempFile = new File(FileUtil.checkDirPath(Environment.getExternalStorageDirectory().getPath() + "/image/"), System.currentTimeMillis() + ".jpg");
//跳转到调用系统相机
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//设置7.0中共享文件,分享路径定义在xml/file_paths.xml
intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".fileProvider", tempFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
} else {
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
}
startActivityForResult(intent, REQUEST_CAPTURE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
switch (requestCode) {
case REQUEST_CAPTURE: //调用系统相机返回
if (resultCode == RESULT_OK) {
gotoClipActivity(Uri.fromFile(tempFile));
}
break;
case REQUEST_PICK: //调用系统相册返回
if (resultCode == RESULT_OK) {
Uri uri = intent.getData();
gotoClipActivity(uri);
}
break;
case REQUEST_CROP_PHOTO: //剪切图片返回
if (resultCode == RESULT_OK) {
final Uri uri = intent.getData();
if (uri == null) {
return;
}
String cropImagePath = getRealFilePathFromUri(getApplicationContext(), uri);
Bitmap bitMap = BitmapFactory.decodeFile(cropImagePath);
if (type == 1) {
headImage1.setImageBitmap(bitMap);
} else {
headImage2.setImageBitmap(bitMap);
}
//此处后面可以将bitMap转为二进制上传后台网络
//......
}
break;
}
}
/**
* 打开截图界面
*/
public void gotoClipActivity(Uri uri) {
if (uri == null) {
return;
}
Intent intent = new Intent();
intent.setClass(this, ClipImageActivity.class);
intent.putExtra("type", type);
intent.setData(uri);
startActivityForResult(intent, REQUEST_CROP_PHOTO);
}
}
最后在AndroidManifest.xml配置如下代码
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="evan.wang.fileProvider"
android:exported="false"
android:grantUriPermissions="true"
tools:ignore="WrongManifestParent">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
不要忘记加读写权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />