这个是之前做的一个demo,在github中能下载到https://github.com/zz7zz7zz/android-cropImage,我是对里面做了修改
效果图如下:
我这个demo只是对github中剪裁的框框样式和一些拉伸区域做了效果
demo的架构如下:
1、主要是对里面的FloatDrawable.java做了修改
package com.open.crop;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
/**
* 头像图片选择框的浮层
* @author Administrator
*
*/
public class FloatDrawable extends Drawable {
private Context mContext;
private Drawable mCropPointDrawable;
//FIXME add
private Drawable mCropPointDrawableLeft;
private Drawable mCropPointDrawableRight;
private Drawable mCropPointDrawableTop;
private Drawable mCropPointDrawableBottom;
private Paint mLinePaint=new Paint();
{
mLinePaint.setARGB(200, 50, 50, 50);
mLinePaint.setStrokeWidth(1F);
mLinePaint.setStyle(Paint.Style.STROKE);
mLinePaint.setAntiAlias(true);
mLinePaint.setColor(Color.WHITE);
}
public FloatDrawable(Context context) {
super();
this.mContext=context;
init();
}
private void init()
{
mCropPointDrawable=mContext.getResources().getDrawable(R.drawable.clip_point);
mCropPointDrawableLeft=mContext.getResources().getDrawable(R.drawable.common_photo_left_normal);
mCropPointDrawableRight=mContext.getResources().getDrawable(R.drawable.common_photo_right_normal);
mCropPointDrawableTop=mContext.getResources().getDrawable(R.drawable.common_photo_top_normal);
mCropPointDrawableBottom=mContext.getResources().getDrawable(R.drawable.common_photo_bottom_normal);
}
public int getCirleWidth()
{
return mCropPointDrawableLeft.getIntrinsicWidth();
}
public int getCirleHeight()
{
return mCropPointDrawableLeft.getIntrinsicHeight();
}
@Override
public void draw(Canvas canvas) {
int left=getBounds().left;
int top=getBounds().top;
int right=getBounds().right;
int bottom=getBounds().bottom;
Rect mRect=new Rect(
left+mCropPointDrawableLeft.getIntrinsicWidth()/2,
top+mCropPointDrawableLeft.getIntrinsicHeight()/2,
right-mCropPointDrawableLeft.getIntrinsicWidth()/2,
bottom-mCropPointDrawableLeft.getIntrinsicHeight()/2);
//方框
canvas.drawRect(mRect, mLinePaint);
//左右边 高度的偏移量
int lx=(bottom - top) / 2 - mCropPointDrawableLeft.getIntrinsicHeight()/2;
mCropPointDrawableLeft.setBounds(left, top + lx, left+mCropPointDrawableLeft.getIntrinsicWidth(), top +lx+mCropPointDrawableLeft.getIntrinsicHeight());
mCropPointDrawableLeft.draw(canvas);
mCropPointDrawableRight.setBounds(right-mCropPointDrawableRight.getIntrinsicWidth(), top + lx, right, top+lx+mCropPointDrawableRight.getIntrinsicHeight());
mCropPointDrawableRight.draw(canvas);
//上
int tx=(right - left) / 2 - mCropPointDrawableLeft.getIntrinsicWidth() / 2;
mCropPointDrawableTop.setBounds(left+tx, top , left+tx+mCropPointDrawableTop.getIntrinsicWidth(), top +mCropPointDrawableTop.getIntrinsicHeight());
mCropPointDrawableTop.draw(canvas);
// //下
mCropPointDrawableBottom.setBounds(left + tx, bottom-mCropPointDrawableBottom.getIntrinsicHeight(), left + tx +mCropPointDrawableBottom.getIntrinsicWidth(), bottom);
mCropPointDrawableBottom.draw(canvas);
}
@Override
public void setBounds(Rect bounds) {
super.setBounds(new Rect(
bounds.left-mCropPointDrawableLeft.getIntrinsicWidth()/2,
bounds.top-mCropPointDrawableLeft.getIntrinsicHeight()/2,
bounds.right+mCropPointDrawableLeft.getIntrinsicWidth()/2,
bounds.bottom+mCropPointDrawableLeft.getIntrinsicHeight()/2));
}
@Override
public void setAlpha(int alpha) {
// TODO Auto-generated method stub
}
@Override
public void setColorFilter(ColorFilter cf) {
// TODO Auto-generated method stub
}
@Override
public int getOpacity() {
// TODO Auto-generated method stub
return 0;
}
}
package com.open.crop;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* 底图不变,浮层缩放
* @author yanglonghui
*
*/
public class CropImageView3 extends View {
//单点触摸的时候
private float oldX=0;
private float oldY=0;
//状态
private final int STATUS_Touch_SINGLE=1;//单点
private final int STATUS_TOUCH_MULTI_START=2;//多点开始
private final int STATUS_TOUCH_MULTI_TOUCHING=3;//多点拖拽中
private int mStatus=STATUS_Touch_SINGLE;
//默认的裁剪图片宽度与高度
private final int defaultCropWidth=300;
private final int defaultCropHeight=300;
private int cropWidth=defaultCropWidth;
private int cropHeight=defaultCropHeight;
private final int EDGE_LT=1;//左上
private final int EDGE_RT=2;//右上
private final int EDGE_LB=3;//左下
private final int EDGE_RB=4;//右下
private final int EDGE_MOVE_IN=5;//里面移动
private final int EDGE_MOVE_OUT=6;//外面移动
private final int EDGE_NONE=7;//外面移动
public int currentEdge=EDGE_NONE;
protected float oriRationWH=0;//原始宽高比率
protected final float maxZoomOut=5.0f;//最大扩大到多少倍
protected final float minZoomIn=0.333333f;//最小缩小到多少倍
protected Drawable mDrawable;//原图
protected FloatDrawable mFloatDrawable;//浮层
protected Rect mDrawableSrc = new Rect();
protected Rect mDrawableDst = new Rect();
protected Rect mDrawableFloat = new Rect();//浮层选择框,就是头像选择框
protected boolean isFrist=true;
private boolean isTouchInSquare=true;
protected Context mContext;
public CropImageView3(Context context) {
super(context);
init(context);
}
public CropImageView3(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CropImageView3(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
@SuppressLint("NewApi")
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();
}
mFloatDrawable=new FloatDrawable(context);//头像选择框
}
public void setDrawable(Drawable mDrawable,int cropWidth,int cropHeight)
{
this.mDrawable=mDrawable;
this.cropWidth=cropWidth;
this.cropHeight=cropHeight;
this.isFrist=true;
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getPointerCount()>1)
{
if(mStatus==STATUS_Touch_SINGLE)
{
mStatus=STATUS_TOUCH_MULTI_START;
}
else if(mStatus==STATUS_TOUCH_MULTI_START)
{
mStatus=STATUS_TOUCH_MULTI_TOUCHING;
}
}
else
{
if(mStatus==STATUS_TOUCH_MULTI_START||mStatus==STATUS_TOUCH_MULTI_TOUCHING)
{
oldX=event.getX();
oldY=event.getY();
}
mStatus=STATUS_Touch_SINGLE;
}
//Log.v("count currentTouch"+currentTouch, "-------");
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
oldX = event.getX();
oldY = event.getY();
currentEdge=getTouchEdge((int)oldX, (int)oldY);
isTouchInSquare=mDrawableFloat.contains((int)event.getX(), (int)event.getY());
Log.v("currentEdge:"+currentEdge, "-------");
break;
case MotionEvent.ACTION_UP:
checkBounds();
break;
case MotionEvent.ACTION_POINTER_1_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
currentEdge=EDGE_NONE;
break;
case MotionEvent.ACTION_MOVE:
if(mStatus==STATUS_TOUCH_MULTI_TOUCHING)
{
}
else if(mStatus==STATUS_Touch_SINGLE)
{
int dx=(int)(event.getX()-oldX);
int dy=(int)(event.getY()-oldY);
oldX=event.getX();
oldY=event.getY();
if(!(dx==0&&dy==0))
{
<span style="color:#ff0000;">switch(currentEdge)</span>
<span style="color:#ff0000;">{
case EDGE_LT://左
mDrawableFloat.set(mDrawableFloat.left+dx, mDrawableFloat.top, mDrawableFloat.right, mDrawableFloat.bottom);
//FIXME 修改
// mDrawableFloat.set(mDrawableFloat.left+dx, mDrawableFloat.top, mDrawableFloat.right, mDrawableFloat.bottom);
break;
case EDGE_RT://右
mDrawableFloat.set(mDrawableFloat.left, mDrawableFloat.top, mDrawableFloat.right+dx, mDrawableFloat.bottom);
break;
case EDGE_LB://上
mDrawableFloat.set(mDrawableFloat.left, mDrawableFloat.top+dy, mDrawableFloat.right, mDrawableFloat.bottom);
break;
case EDGE_RB://下
mDrawableFloat.set(mDrawableFloat.left, mDrawableFloat.top, mDrawableFloat.right, mDrawableFloat.bottom+dy);
break;
case EDGE_MOVE_IN:
if(isTouchInSquare)
{
mDrawableFloat.offset((int)dx, (int)dy);
}
break;
case EDGE_MOVE_OUT:
break;
}</span>
mDrawableFloat.sort();
invalidate();
}
}
break;
}
return true;
}
public int getTouchEdge(int eventX,int eventY)
{
//左右
int lt=(mFloatDrawable.getBounds().bottom-mFloatDrawable.getBounds().top )/2-mFloatDrawable.getCirleHeight()/2;
int lb=(mFloatDrawable.getBounds().bottom-mFloatDrawable.getBounds().top )/2+mFloatDrawable.getCirleHeight()/2;
//上下
int tl=(mFloatDrawable.getBounds().right-mFloatDrawable.getBounds().left)/2 -mFloatDrawable.getCirleWidth()/2;
int tr=(mFloatDrawable.getBounds().right-mFloatDrawable.getBounds().left)/2 +mFloatDrawable.getCirleWidth()/2;
if(mFloatDrawable.getBounds().left<=eventX&&eventX<(mFloatDrawable.getBounds().left+mFloatDrawable.getCirleWidth())
)
{
return EDGE_LT;//左
}
else if((mFloatDrawable.getBounds().right-mFloatDrawable.getCirleWidth())<=eventX&&eventX<mFloatDrawable.getBounds().right
)
{
return EDGE_RT;//右
}
else if((mFloatDrawable.getBounds().top-mFloatDrawable.getCirleHeight()/2)<=eventY&&eventY<(mFloatDrawable.getBounds().top+mFloatDrawable.getCirleHeight()/2))
{
return EDGE_LB;//上
}
else if((mFloatDrawable.getBounds().bottom-mFloatDrawable.getCirleHeight())<=eventY&&eventY<(mFloatDrawable.getBounds().bottom))
{
return EDGE_RB;//下
}
else if(mFloatDrawable.getBounds().contains(eventX,eventY))
{
return EDGE_MOVE_IN;//里面移动
}
return EDGE_MOVE_OUT;
}
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
if (mDrawable == null) {
return; // couldn't resolve the URI
}
if (mDrawable.getIntrinsicWidth() == 0 || mDrawable.getIntrinsicHeight() == 0) {
return; // nothing to draw (empty bounds)
}
configureBounds();
mDrawable.draw(canvas);
canvas.save();
canvas.clipRect(mDrawableFloat, Region.Op.DIFFERENCE);
canvas.drawColor(Color.parseColor("#a0000000"));
canvas.restore();
mFloatDrawable.draw(canvas);
}
protected void configureBounds()
{
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);
int floatWidth=dipTopx(mContext, cropWidth);
int floatHeight=dipTopx(mContext, cropHeight);
if(floatWidth>getWidth())
{
floatWidth=getWidth();
floatHeight=cropHeight*floatWidth/cropWidth;
}
if(floatHeight>getHeight())
{
floatHeight=getHeight();
floatWidth=cropWidth*floatHeight/cropHeight;
}
int floatLeft=(getWidth()-floatWidth)/2;
int floatTop = (getHeight()-floatHeight)/2;
mDrawableFloat.set(floatLeft, floatTop,floatLeft+floatWidth, floatTop+floatHeight);
isFrist=false;
}
mDrawable.setBounds(mDrawableDst);
mFloatDrawable.setBounds(mDrawableFloat);
}
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();
}
}
public Bitmap getCropImage()
{
Bitmap tmpBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.RGB_565);
Canvas canvas = new Canvas(tmpBitmap);
mDrawable.draw(canvas);
Matrix matrix=new Matrix();
float scale=(float)(mDrawableSrc.width())/(float)(mDrawableDst.width());
matrix.postScale(scale, scale);
Bitmap ret = Bitmap.createBitmap(tmpBitmap, mDrawableFloat.left, mDrawableFloat.top, mDrawableFloat.width(), mDrawableFloat.height(), matrix, true);
tmpBitmap.recycle();
tmpBitmap=null;
return ret;
}
public int dipTopx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
如果没有积分需要这个效果的话,可以给我留言