以下是在图片裁剪类的原型上修改过的:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.hmy.android.allforme.util.DimenUtil;
/**
* Created by hmy
*/
public class CropImageView extends View {
protected Context mContext;
private DimenUtil dimenUtil;
// 在touch重要用到的点,
private float mX_1 = 0;
private float mY_1 = 0;
// 当前状态
private TouchStatus touchStatus = TouchStatus.STATUS_SINGLE;
// 默认裁剪的宽高
private int cropWidth = 0;
private int cropHeight = 0;
//手指触摸位置
public TouchPosition touchPosition = TouchPosition.EDGE_NONE;
protected Drawable mDrawable;//被裁剪对象
protected FloatDrawable mFloatDrawable;//裁剪层
protected Rect mDrawableSrc = new Rect();// 图片Rect变换时的Rect
protected Rect mDrawableDst = new Rect();// 图片Rect
protected Rect mDrawableFloat = new Rect();// 裁剪层的Rect
private boolean isTouchInSquare = true;//当前触点是否在裁剪框内
protected boolean isFrist = true;//
protected float oriRationWH = 0;//
private boolean isCropEnable = true;
public void setCropEnable(boolean cropEnable) {
this.isCropEnable = cropEnable;
}
/**
* 手指触摸状态
*/
public enum TouchStatus {
STATUS_SINGLE,//单指触摸
STATUS_MULTI_START,//多指触摸开始
STATUS_MULTI_TOUCHING,//多指触摸中
}
/**
* 手指触摸位置
*/
public enum TouchPosition {
EDGE_LT,//左上角
EDGE_RT,//右上角
EDGE_LB,//左下角
EDGE_RB,//右下角
EDGE_MOVE_IN,//裁剪框内部
EDGE_MOVE_OUT,//裁剪框外部
EDGE_NONE,//nothing
}
public CropImageView(Context context) {
super(context);
init(context);
}
public CropImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CropImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
/**
* 初始化
*
* @param context
*/
private void init(Context context) {
this.mContext = context;
try {
if (android.os.Build.VERSION.SDK_INT >= 11) {
this.setLayerType(LAYER_TYPE_SOFTWARE, null);
}
} catch (Exception e) {
e.printStackTrace();
}
this.isFrist = true;
mFloatDrawable = new FloatDrawable(context);
dimenUtil = new DimenUtil(mContext);
cropWidth = dimenUtil.getScreenWidth();
cropHeight = dimenUtil.getScreenHeight();
}
/**
* 设置被裁剪样本
*
* @param mDrawable
* @param cropWidth
* @param cropHeight
*/
public void setDrawable(Drawable mDrawable, int cropWidth, int cropHeight) {
this.cropWidth = cropWidth;
this.cropHeight = cropHeight;
this.mDrawable = mDrawable;
invalidate();
}
/**
* 设置被裁剪样本
*
* @param mDrawable
*/
public void setDrawable(Drawable mDrawable) {
this.mDrawable = mDrawable;
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getPointerCount() > 1) {
switch (touchStatus) {
case STATUS_SINGLE:
touchStatus = TouchStatus.STATUS_MULTI_START;
break;
case STATUS_MULTI_START:
touchStatus = TouchStatus.STATUS_MULTI_TOUCHING;
break;
}
} else {
switch (touchStatus) {
case STATUS_MULTI_TOUCHING:
case STATUS_MULTI_START:
mX_1 = event.getX();
mY_1 = event.getY();
break;
}
touchStatus = TouchStatus.STATUS_SINGLE;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mX_1 = event.getX();
mY_1 = event.getY();
touchPosition = getTouchPosition(mX_1, mY_1);
isTouchInSquare = mDrawableFloat.contains((int) event.getX(),
(int) event.getY());
break;
case MotionEvent.ACTION_UP:
checkBounds();
break;
case MotionEvent.ACTION_POINTER_UP:
touchPosition = TouchPosition.EDGE_NONE;
break;
case MotionEvent.ACTION_MOVE:
switch (touchStatus) {
case STATUS_MULTI_TOUCHING:
//多指触摸中...
break;
case STATUS_SINGLE:
int dx = (int) (event.getX() - mX_1);
int dy = (int) (event.getY() - mY_1);
mX_1 = event.getX();
mY_1 = event.getY();
// 根據得到的那一个角,并且变换Rect
if (!(dx == 0 && dy == 0)) {
switch (touchPosition) {
case EDGE_LT:
mDrawableFloat.set(mDrawableFloat.left + dx,
mDrawableFloat.top + dy, mDrawableFloat.right,
mDrawableFloat.bottom);
break;
case EDGE_RT:
mDrawableFloat.set(mDrawableFloat.left,
mDrawableFloat.top + dy, mDrawableFloat.right
+ dx, mDrawableFloat.bottom);
break;
case EDGE_LB:
mDrawableFloat.set(mDrawableFloat.left + dx,
mDrawableFloat.top, mDrawableFloat.right,
mDrawableFloat.bottom + dy);
break;
case EDGE_RB:
mDrawableFloat.set(mDrawableFloat.left,
mDrawableFloat.top, mDrawableFloat.right + dx,
mDrawableFloat.bottom + dy);
break;
case EDGE_MOVE_IN:
if (isTouchInSquare) {
mDrawableFloat.offset(dx, dy);
}
break;
case EDGE_MOVE_OUT:
//这部分可以控制图片的缩放,位移
break;
}
mDrawableFloat.sort();
invalidate();
}
break;
}
break;
}
return true;
}
/**
* 根据初触摸点判断是触摸的Rect哪一个角
*/
public TouchPosition getTouchPosition(float eventX, float eventY) {
if (mFloatDrawable.getBounds().left <= eventX
&& eventX < (mFloatDrawable.getBounds().left + mFloatDrawable
.getBorderWidth())
&& mFloatDrawable.getBounds().top <= eventY
&& eventY < (mFloatDrawable.getBounds().top + mFloatDrawable
.getBorderHeight())) {
return TouchPosition.EDGE_LT;
} else if ((mFloatDrawable.getBounds().right - mFloatDrawable
.getBorderWidth()) <= eventX
&& eventX < mFloatDrawable.getBounds().right
&& mFloatDrawable.getBounds().top <= eventY
&& eventY < (mFloatDrawable.getBounds().top + mFloatDrawable
.getBorderHeight())) {
return TouchPosition.EDGE_RT;
} else if (mFloatDrawable.getBounds().left <= eventX
&& eventX < (mFloatDrawable.getBounds().left + mFloatDrawable
.getBorderWidth())
&& (mFloatDrawable.getBounds().bottom - mFloatDrawable
.getBorderHeight()) <= eventY
&& eventY < mFloatDrawable.getBounds().bottom) {
return TouchPosition.EDGE_LB;
} else if ((mFloatDrawable.getBounds().right - mFloatDrawable
.getBorderWidth()) <= eventX
&& eventX < mFloatDrawable.getBounds().right
&& (mFloatDrawable.getBounds().bottom - mFloatDrawable
.getBorderHeight()) <= eventY
&& eventY < mFloatDrawable.getBounds().bottom) {
return TouchPosition.EDGE_RB;
} else if (mFloatDrawable.getBounds().contains((int) eventX, (int) eventY)) {
return TouchPosition.EDGE_MOVE_IN;
}
return TouchPosition.EDGE_MOVE_OUT;
}
@Override
protected void onDraw(Canvas canvas) {
//如果没有设置裁剪样本,则赋值一个空的图层
if (mDrawable == null) {
mDrawable = new BitmapDrawable(mContext.getResources(), getEmptyBitmap());
}
//设定 界限 规则
initBounds();
// 画图片
mDrawable.draw(canvas);
//画裁剪框
drawCropUI(canvas);
}
/**
* 绘制裁剪框样式
*
* @param canvas
*/
private void drawCropUI(Canvas canvas) {
if (!isCropEnable) {
return;
}
canvas.save();
// 在画布上画浮层FloatDrawable,Region.Op.DIFFERENCE是表示Rect交集的补集
canvas.clipRect(mDrawableFloat, Region.Op.DIFFERENCE);
// 在交集的补集上画上灰色用来区分
canvas.drawColor(Color.parseColor("#a0000000"));
canvas.restore();
// 画浮层
mFloatDrawable.draw(canvas);
}
/**
* 初始化 界限 参数,在onDraw方法中调用;
* isFirst的目的是下面对mDrawableSrc和mDrawableFloat只初始化一次;
* 之后的变化是根据touch事件来变化的,而不是每次执行重新对mDrawableSrc和mDrawableFloat进行设置
*/
protected void initBounds() {
if (isFrist) {
oriRationWH = ((float) mDrawable.getIntrinsicWidth())
/ ((float) mDrawable.getIntrinsicHeight());
final float scale = mContext.getResources().getDisplayMetrics().density;
int w = Math.min(getWidth(), (int) (mDrawable.getIntrinsicWidth()
* scale + 0.5f));
int h = (int) (w / oriRationWH);
int left = (getWidth() - w) / 2;
int top = (getHeight() - h) / 2;
int right = left + w;
int bottom = top + h;
mDrawableSrc.set(left, top, right, bottom);
mDrawableDst.set(mDrawableSrc);
if (cropWidth > getWidth()) {
cropWidth = getWidth();
cropHeight = cropHeight * cropWidth / cropWidth;
}
if (cropHeight > getHeight()) {
cropHeight = getHeight();
cropWidth = cropWidth * cropHeight / cropHeight;
}
int floatLeft = (getWidth() - cropWidth) / 2;
int floatTop = (getHeight() - cropHeight) / 2;
mDrawableFloat.set(floatLeft, floatTop, floatLeft + cropWidth,
floatTop + cropHeight);
isFrist = false;
}
mDrawable.setBounds(mDrawableDst);
mFloatDrawable.setBounds(mDrawableFloat);
}
/**
* 在up事件中调用了该方法,目的是检查是否把浮层拖出了屏幕
*/
protected void checkBounds() {
int newLeft = mDrawableFloat.left;
int newTop = mDrawableFloat.top;
boolean isChange = false;
if (mDrawableFloat.left < getLeft()) {
newLeft = getLeft();
isChange = true;
}
if (mDrawableFloat.top < getTop()) {
newTop = getTop();
isChange = true;
}
if (mDrawableFloat.right > getRight()) {
newLeft = getRight() - mDrawableFloat.width();
isChange = true;
}
if (mDrawableFloat.bottom > getBottom()) {
newTop = getBottom() - mDrawableFloat.height();
isChange = true;
}
mDrawableFloat.offsetTo(newLeft, newTop);
if (isChange) {
invalidate();
}
}
/**
* 进行图片的裁剪,所谓的裁剪就是根据Drawable的新的坐标在画布上创建一张新的图片
*/
public Bitmap getCropImage() {
Bitmap result = null;
if (!isCropEnable) {
return result;
}
Bitmap tmpBitmap = getEmptyBitmap();
Canvas canvas = new Canvas(tmpBitmap);
mDrawable.draw(canvas);
result = Bitmap.createBitmap(tmpBitmap, mDrawableFloat.left,
mDrawableFloat.top, mDrawableFloat.width(),
mDrawableFloat.height());
recycle(tmpBitmap);
return result;
}
private void recycle(Bitmap bitmap) {
try {
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
System.gc();
}
} catch (Exception var2) {
var2.printStackTrace();
}
}
private Bitmap getEmptyBitmap() {
return Bitmap.createBitmap(dimenUtil.getScreenWidth(), dimenUtil.getScreenHeight(), Bitmap.Config.RGB_565);
}
}
以上,类中用到的工具类:
import android.content.Context;
import android.view.View;
/**
* Created by hmy
*/
public class DimenUtil {
private Context mContext;
private float density = -1.0F;
private int widthPixels = -1;
private int heightPixels = -1;
public DimenUtil(Context context) {
this.mContext = context;
}
public float getDensity() {
if (density <= 0.0F) {
density = mContext.getResources().getDisplayMetrics().density;
}
return density;
}
public int dip2px(float dpValue) {
return (int) (dpValue * getDensity() + 0.5F);
}
public int px2dip(float pxValue) {
return (int) (pxValue / getDensity() + 0.5F);
}
public int getScreenWidth() {
if (widthPixels <= 0) {
widthPixels = mContext.getResources().getDisplayMetrics().widthPixels;
}
return widthPixels;
}
public int getScreenHeight() {
if (heightPixels <= 0) {
heightPixels = mContext.getResources().getDisplayMetrics().heightPixels;
}
return heightPixels;
}
}
还需要把裁剪框封装到另一个控件中,使用的时候将下面的控件作为根布局,调用相关方法就可以截屏其包含的view:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
/**
* Created by hmy
*/
public class ScreenShotView extends FrameLayout {
private Context mContext;
private CropImageView mCropIv;
private int mWidth = 0;
private int mHeight = 0;
public ScreenShotView(Context context) {
super(context);
init(context);
}
public ScreenShotView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ScreenShotView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
this.mContext = context;
mCropIv = new CropImageView(mContext);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
checkChildView();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
this.mWidth = this.getWidth();
this.mHeight = this.getHeight();
}
/**
* 检查子view
*/
private void checkChildView() {
int count = this.getChildCount();
if (count != 1) {
throw new RuntimeException("ScreenShotView can only have one child view!");
} else {
this.addView(mCropIv);
initScreenView();
}
}
/**
* 初始化截屏view
*/
private void initScreenView() {
final View screenView = this.getChildAt(0);
screenView.buildDrawingCache();
// 允许当前窗口保存缓存信息
screenView.setDrawingCacheEnabled(true);
//view加载完成时回调
screenView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
try {
//获取bitmap
Bitmap bmp = Bitmap.createBitmap(screenView.getDrawingCache(), 0, 0, mWidth, mHeight);
// 销毁缓存信息
screenView.destroyDrawingCache();
mCropIv.setDrawable(new BitmapDrawable(mContext.getResources(), bmp));
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* 获取截取框内的图片
*
* @return
*/
public Bitmap getCropImage() {
return mCropIv.getCropImage();
}
public void setCropEnable(boolean enable) {
mCropIv.setCropEnable(enable);
}
}
使用方法:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.hmy.android.allforme.view.ScreenShotView
android:id="@+id/main_crop"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/bj" />
</com.hmy.android.allforme.view.ScreenShotView>
<ImageView
android:id="@+id/main_iv"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignParentRight="true"
android:background="#afff"
android:src="@mipmap/groundoverlay" />
</RelativeLayout>
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import com.hmy.android.allforme.R;
import com.hmy.android.allforme.view.ScreenShotView;
public class MainActivity extends Activity {
private ScreenShotView imageView;
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ScreenShotView) findViewById(R.id.main_crop);
iv = (ImageView) findViewById(R.id.main_iv);
iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Bitmap mBitmap = imageView.getCropImage();
iv.setImageBitmap(mBitmap);
}
});
}
}