1 自定义可裁剪的VIew,其中的mBmpPath,是图片路径,从其他页面传过来的,测试时可改成本地文件地址。80385897
主要功能,自定义裁剪框的初始位置,手动伸缩裁剪框
package com.minzh.onemedia.widget;
import android.content.Context;
import android.drm.DrmStore.RightsStatus;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
public class MyCropView extends ImageView {
// Private Constants ///
private static final float BMP_LEFT = 5f;
private static final float BMP_TOP = 5f;
private static float DEFAULT_BORDER_RECT_WIDTH = 200f;
private static float DEFAULT_BORDER_RECT_HEIGHT = 200f;
private static final int POS_TOP_LEFT = 0;
private static final int POS_TOP_RIGHT = 1;
private static final int POS_BOTTOM_LEFT = 2;
private static final int POS_BOTTOM_RIGHT = 3;
private static final int POS_TOP = 4;
private static final int POS_BOTTOM = 5;
private static final int POS_LEFT = 6;
private static final int POS_RIGHT = 7;
private static final int POS_CENTER = 8;
// this constant would be best to use event number
private static final float BORDER_LINE_WIDTH = 6f;
private static final float BORDER_CORNER_LENGTH = 30f;
private static final float TOUCH_FIELD = 10f;
// Member Variables
private String mBmpPath;
private Bitmap mBmpToCrop;
private RectF mBmpBound;
private Paint mBmpPaint;
private Paint mBorderPaint;// 裁剪区边框
private Paint mGuidelinePaint;
private Paint mCornerPaint;
private Paint mBgPaint;
// private RectF mDefaultBorderBound;
private RectF mBorderBound;
private PointF mLastPoint = new PointF();
private float mBorderWidth;
private float mBorderHeight;
private int touchPos;
// Constructors
public MyCropView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init(context);
}
public MyCropView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
// View Methods
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO Auto-generated method stub
// super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
// super.onDraw(canvas);
this.setScaleType(ImageView.ScaleType.FIT_CENTER);
if (mBmpPath != null) {
canvas.drawBitmap(mBmpToCrop, null, mBmpBound, mBmpPaint);
canvas.drawRect(mBorderBound.left, mBorderBound.top, mBorderBound.right, mBorderBound.bottom, mBorderPaint);
drawGuidlines(canvas);
drawBackground(canvas);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
// super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setLastPosition(event);
getParent().requestDisallowInterceptTouchEvent(true);
// onActionDown(event.getX(), event.getY());
touchPos = detectTouchPosition(event.getX(), event.getY());
break;
case MotionEvent.ACTION_MOVE:
onActionMove(event.getX(), event.getY());
setLastPosition(event);
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
// Public Methods //
public String getBmpPath() {
return mBmpPath;
}
public void setBmpPath(String picPath) {
this.mBmpPath = picPath;
setBmp();
}
public Bitmap getCroppedImage() {
// 等比例充满屏幕宽度的情况下,裁剪框等比例缩减到图片实际尺寸的裁剪位置
int imgWSource=mBmpToCrop.getWidth();
int imgHSource=mBmpToCrop.getHeight();
double rateW=imgWSource*1.0/imgW;
double rateH=imgHSource*1.0/imgH;
int left=(int) (rateW*mBorderBound.left);
left=left==0?1:left;
int top= (int) (rateH* mBorderBound.top);
top=top==0?1:top;
int width=(int) (rateW* mBorderWidth);
int height=(int) (rateH* mBorderHeight);
if(left+width>imgWSource){
width=imgWSource-left;
}
if(top+height>imgHSource){
height=imgHSource-top;
}
Bitmap bit=Bitmap.createBitmap(mBmpToCrop, left, top, width,
height);
return bit;
}
// Private Methods /
private void init(Context context) {
mBmpPaint = new Paint();
// 以下是抗锯齿
mBmpPaint.setAntiAlias(true);// 防止边缘的锯齿
mBmpPaint.setFilterBitmap(true);// 对位图进行滤波处理
mBorderPaint = new Paint();
mBorderPaint.setStyle(Style.STROKE);
mBorderPaint.setColor(Color.parseColor("#AAFFFFFF"));
mBorderPaint.setStrokeWidth(BORDER_LINE_WIDTH);
mGuidelinePaint = new Paint();
mGuidelinePaint.setColor(Color.parseColor("#AAFFFFFF"));
mGuidelinePaint.setStrokeWidth(1f);
mCornerPaint = new Paint();
mBgPaint = new Paint();
mBgPaint.setColor(Color.parseColor("#B0000000"));
mBgPaint.setAlpha(150);
}
int w_screen,h_screen;
int imgW,imgH;
private void setBmp() {
DisplayMetrics dm =getResources().getDisplayMetrics();
w_screen = dm.widthPixels;
h_screen = dm.heightPixels;
mBmpToCrop = BitmapFactory.decodeFile(mBmpPath);
imgW=mBmpToCrop.getWidth();
imgH=mBmpToCrop.getHeight();
// if(w_screen*1.0/h_screen<imgW*1.0/imgH){
// //宽度为主显示图片
// imgH=imgH*w_screen/imgW;
// imgW=w_screen;
// }else{
// //高度为主显示图片
// imgW=imgW*h_screen/imgH;
// imgH=h_screen;
// }
//宽度为主显示图片,等比例充满屏幕宽度
imgH=imgH*w_screen/imgW;
imgW=w_screen;
//图片大小
mBmpBound = new RectF();
mBmpBound.left = BMP_LEFT;
mBmpBound.top = BMP_TOP;
mBmpBound.right = imgW-mBmpBound.left;
mBmpBound.bottom =imgH-mBmpBound.top;
//定义 裁剪框大小
DEFAULT_BORDER_RECT_WIDTH= imgW-mBmpBound.left;
DEFAULT_BORDER_RECT_HEIGHT= DEFAULT_BORDER_RECT_WIDTH*4/5;
// 使裁剪框一开始出现在图片的中心位置
// mBorderBound = new RectF();
// mBorderBound.left = (mBmpBound.left + mBmpBound.right - DEFAULT_BORDER_RECT_WIDTH) / 2;
// mBorderBound.top = (mBmpBound.top + mBmpBound.bottom - DEFAULT_BORDER_RECT_HEIGHT) / 2;
// mBorderBound.right = mBorderBound.left + DEFAULT_BORDER_RECT_WIDTH;
// mBorderBound.bottom = mBorderBound.top + DEFAULT_BORDER_RECT_HEIGHT;
mBorderBound = new RectF();
mBorderBound.left = (mBmpBound.left + mBmpBound.right - DEFAULT_BORDER_RECT_WIDTH) / 2;
float top = (mBmpBound.top + mBmpBound.bottom - DEFAULT_BORDER_RECT_HEIGHT);
mBorderBound.top=top<=0?1:top;
mBorderBound.right = mBorderBound.left + DEFAULT_BORDER_RECT_WIDTH;
mBorderBound.bottom = mBorderBound.top + DEFAULT_BORDER_RECT_HEIGHT;
getBorderEdgeLength();
invalidate();
}
private void drawBackground(Canvas canvas) {
/*-
-------------------------------------
| top |
-------------------------------------
| | | |<——————————mBmpBound
| | | |
| left | | right |
| | | |
| | <─┼───────┼────mBorderBound
-------------------------------------
| bottom |
-------------------------------------
*/
// Draw "top", "bottom", "left", then "right" quadrants.
// because the border line width is larger than 1f, in order to draw a complete border rect ,
// i have to change zhe rect coordinate to draw
float delta = BORDER_LINE_WIDTH / 2;
float left = mBorderBound.left - delta;
float top = mBorderBound.top - delta;
float right = mBorderBound.right + delta;
float bottom = mBorderBound.bottom + delta;
// -------------------------------------------------------------------------------移动到上下两端会多出来阴影
canvas.drawRect(mBmpBound.left, mBmpBound.top, mBmpBound.right, top, mBgPaint);
canvas.drawRect(mBmpBound.left, bottom, mBmpBound.right, mBmpBound.bottom, mBgPaint);
canvas.drawRect(mBmpBound.left, top, left, bottom, mBgPaint);
canvas.drawRect(right, top, mBmpBound.right, bottom, mBgPaint);
}
// 画裁剪区域中间的参考线
private void drawGuidlines(Canvas canvas) {
// Draw vertical guidelines.
final float oneThirdCropWidth = mBorderBound.width() / 3;
final float x1 = mBorderBound.left + oneThirdCropWidth;
canvas.drawLine(x1, mBorderBound.top, x1, mBorderBound.bottom, mGuidelinePaint);
final float x2 = mBorderBound.right - oneThirdCropWidth;
canvas.drawLine(x2, mBorderBound.top, x2, mBorderBound.bottom, mGuidelinePaint);
// Draw horizontal guidelines.
final float oneThirdCropHeight = mBorderBound.height() / 3;
final float y1 = mBorderBound.top + oneThirdCropHeight;
canvas.drawLine(mBorderBound.left, y1, mBorderBound.right, y1, mGuidelinePaint);
final float y2 = mBorderBound.bottom - oneThirdCropHeight;
canvas.drawLine(mBorderBound.left, y2, mBorderBound.right, y2, mGuidelinePaint);
}
private void onActionDown(float x, float y) {
}
private void onActionMove(float x, float y) {
float deltaX = x - mLastPoint.x;
float deltaY = y - mLastPoint.y;
// 这里先不考虑裁剪框放最大的情况
switch (touchPos) {
case POS_CENTER:
mBorderBound.left += deltaX;
// fix border position
if (mBorderBound.left < mBmpBound.left)
mBorderBound.left = mBmpBound.left;
if (mBorderBound.left > mBmpBound.right - mBorderWidth)
mBorderBound.left = mBmpBound.right - mBorderWidth;
mBorderBound.top += deltaY;
if (mBorderBound.top < mBmpBound.top)
mBorderBound.top = mBmpBound.top;
if (mBorderBound.top > mBmpBound.bottom - mBorderHeight)
mBorderBound.top = mBmpBound.bottom - mBorderHeight;
mBorderBound.right = mBorderBound.left + mBorderWidth;
mBorderBound.bottom = mBorderBound.top + mBorderHeight;
break;
case POS_TOP:
resetTop(deltaY);
break;
case POS_BOTTOM:
resetBottom(deltaY);
break;
case POS_LEFT:
resetLeft(deltaX);
break;
case POS_RIGHT:
resetRight(deltaX);
break;
case POS_TOP_LEFT:
resetTop(deltaY);
resetLeft(deltaX);
break;
case POS_TOP_RIGHT:
resetTop(deltaY);
resetRight(deltaX);
break;
case POS_BOTTOM_LEFT:
resetBottom(deltaY);
resetLeft(deltaX);
break;
case POS_BOTTOM_RIGHT:
resetBottom(deltaY);
resetRight(deltaX);
break;
default:
break;
}
invalidate();
}
private void onActionUp(float x, float y) {
}
private int detectTouchPosition(float x, float y) {
if (x > mBorderBound.left + TOUCH_FIELD && x < mBorderBound.right - TOUCH_FIELD
&& y > mBorderBound.top + TOUCH_FIELD && y < mBorderBound.bottom - TOUCH_FIELD)
return POS_CENTER;
if (x > mBorderBound.left + BORDER_CORNER_LENGTH && x < mBorderBound.right - BORDER_CORNER_LENGTH) {
if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + TOUCH_FIELD)
return POS_TOP;
if (y > mBorderBound.bottom - TOUCH_FIELD && y < mBorderBound.bottom + TOUCH_FIELD)
return POS_BOTTOM;
}
if (y > mBorderBound.top + BORDER_CORNER_LENGTH && y < mBorderBound.bottom - BORDER_CORNER_LENGTH) {
if (x > mBorderBound.left - TOUCH_FIELD && x < mBorderBound.left + TOUCH_FIELD)
return POS_LEFT;
if (x > mBorderBound.right - TOUCH_FIELD && x < mBorderBound.right + TOUCH_FIELD)
return POS_RIGHT;
}
// 前面的逻辑已经排除掉了几种情况 所以后面的 ┏ ┓ ┗ ┛ 边角就按照所占区域的方形来判断就可以了
if (x > mBorderBound.left - TOUCH_FIELD && x < mBorderBound.left + BORDER_CORNER_LENGTH) {
if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + BORDER_CORNER_LENGTH)
return POS_TOP_LEFT;
if (y > mBorderBound.bottom - BORDER_CORNER_LENGTH && y < mBorderBound.bottom + TOUCH_FIELD)
return POS_BOTTOM_LEFT;
}
if (x > mBorderBound.right - BORDER_CORNER_LENGTH && x < mBorderBound.right + TOUCH_FIELD) {
if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + BORDER_CORNER_LENGTH)
return POS_TOP_RIGHT;
if (y > mBorderBound.bottom - BORDER_CORNER_LENGTH && y < mBorderBound.bottom + TOUCH_FIELD)
return POS_BOTTOM_RIGHT;
}
return -1;
}
private void setLastPosition(MotionEvent event) {
mLastPoint.x = event.getX();
mLastPoint.y = event.getY();
}
private void getBorderEdgeLength() {
mBorderWidth = mBorderBound.width();
mBorderHeight = mBorderBound.height();
}
private void getBorderEdgeWidth() {
mBorderWidth = mBorderBound.width();
}
private void getBorderEdgeHeight() {
mBorderHeight = mBorderBound.height();
}
private void resetLeft(float delta) {
mBorderBound.left += delta;
getBorderEdgeWidth();
fixBorderLeft();
}
private void resetTop(float delta) {
mBorderBound.top += delta;
getBorderEdgeHeight();
fixBorderTop();
}
private void resetRight(float delta) {
mBorderBound.right += delta;
getBorderEdgeWidth();
fixBorderRight();
}
private void resetBottom(float delta) {
mBorderBound.bottom += delta;
getBorderEdgeHeight();
fixBorderBottom();
}
private void fixBorderLeft() {
// fix left
if (mBorderBound.left < mBmpBound.left)
mBorderBound.left = mBmpBound.left;
if (mBorderWidth < 2 * BORDER_CORNER_LENGTH)
mBorderBound.left = mBorderBound.right - 2 * BORDER_CORNER_LENGTH;
}
private void fixBorderTop() {
// fix top
if (mBorderBound.top < mBmpBound.top)
mBorderBound.top = mBmpBound.top;
if (mBorderHeight < 2 * BORDER_CORNER_LENGTH)
mBorderBound.top = mBorderBound.bottom - 2 * BORDER_CORNER_LENGTH;
}
private void fixBorderRight() {
// fix right
if (mBorderBound.right > mBmpBound.right)
mBorderBound.right = mBmpBound.right;
if (mBorderWidth < 2 * BORDER_CORNER_LENGTH)
mBorderBound.right = mBorderBound.left + 2 * BORDER_CORNER_LENGTH;
}
private void fixBorderBottom() {
// fix bottom
if (mBorderBound.bottom > mBmpBound.bottom)
mBorderBound.bottom = mBmpBound.bottom;
if (mBorderHeight < 2 * BORDER_CORNER_LENGTH)
mBorderBound.bottom = mBorderBound.top + 2 * BORDER_CORNER_LENGTH;
}
}
2 Activty
package com.minzh.onemedia.maintain;
import java.io.File;
import java.io.FileOutputStream;
import com.minzh.onemedia.R;
import com.minzh.onemedia.widget.MyCropView;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ScrollView;
public class CropImgActivity extends Activity {
private MyCropView myCropView;
private Button btnCrop;
private Button btnCancel;
private ScrollView sv;
// 假设从图片选择器传递来的图片路径如下
private String CROP_IMAGE_PATH = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mycrop);
myCropView = (MyCropView) findViewById(R.id.myCropView);
btnCrop = (Button) findViewById(R.id.btn_crop);
btnCancel = (Button) findViewById(R.id.btn_cancel);
sv = (ScrollView) findViewById(R.id.scrollview);
CROP_IMAGE_PATH=getIntent().getStringExtra("fileImgPath");
myCropView.setBmpPath(CROP_IMAGE_PATH);
btnCrop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Bitmap croppedImage = myCropView.getCroppedImage();
File f = new File(CROP_IMAGE_PATH);
if (f.exists()) {
f.delete();
}
try {
FileOutputStream out = new FileOutputStream(f);
croppedImage.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setResult(RESULT_OK);
finish();
}
});
btnCancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
finish();
}
});
sv.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
myCropView.getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
});
}
int REQUEST_CODE_IMGZOOM=1001;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
3 布局文件
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/scrollview"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp" >
<com.minzh.onemedia.widget.MyCropView
android:id="@+id/myCropView"
android:layout_width="match_parent"
android:layout_height="600dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_alignParentBottom="true" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" >
<Button
android:id="@+id/btn_cancel"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="取消" />
<Button
android:id="@+id/btn_crop"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:text="确定" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
</ScrollView>
4 效果图