不多说,直接上代码(裁剪的代码摘自网络。)(项目可运行)
主要是系统自身的剪切方式在有些机型上会程序崩溃的问题。
1 package com.jichun.activity;
2
3 import java.io.FileNotFoundException;
4
5 import com.jichun.view.CropCanvas;
6
7 import android.app.Activity;
8 import android.content.ContentResolver;
9 import android.content.Intent;
10 import android.graphics.Bitmap;
11 import android.graphics.BitmapFactory;
12 import android.net.Uri;
13 import android.os.Bundle;
14 import android.view.View;
15 import android.view.View.OnClickListener;
16 import android.widget.ImageButton;
17 import android.widget.ImageView;
18
19 public class MainActivity extends Activity {
20 private CropCanvas canvas = null;
21
22 /** Called when the activity is first created. */
23 @Override
24 public void onCreate(Bundle savedInstanceState) {
25 super.onCreate(savedInstanceState);
26 setContentView(R.layout.main);
27 //创建确定按钮
28 ImageButton confirmBtn = (ImageButton) findViewById(R.id.confirm_button);
29 confirmBtn.setOnClickListener(new OnClickListener() {
30
31 @Override
32 public void onClick(View view) {
33 confirmFunction();
34 }
35 });
36 ImageButton exitBtn = (ImageButton) findViewById(R.id.exit_button);
37 exitBtn.setOnClickListener(new OnClickListener() {
38
39 @Override
40 public void onClick(View view) {
41 exitFunction(view);
42 }
43 });
44 this.gallery();
45 }
46
47 /*
48 * 从相册获取
49 */
50 public void gallery() {
51 // 激活系统图库,选择一张图片
52 Intent intent = new Intent(Intent.ACTION_PICK);
53 intent.setType("image/*");
54 // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_GALLERY
55 startActivityForResult(intent, 112);
56 }
57
58 @Override
59 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
60 super.onActivityResult(requestCode, resultCode, data);
61 if (requestCode == 112) {
62 // 从相册返回的数据
63 if (data != null) {
64 // 得到图片的全路径
65 Uri uri = data.getData();
66 ContentResolver content_resolver = this.getContentResolver();
67 try {
68 Bitmap bmp = BitmapFactory.decodeStream(content_resolver.openInputStream(uri));
69 canvas = (CropCanvas)findViewById(R.id.myCanvas);
70 canvas.setBitmap(bmp);
71 } catch (FileNotFoundException e) {
72 // TODO Auto-generated catch block
73 e.printStackTrace();
74 }
75 }
76 }
77
78 }
79
80 public void confirmFunction(){
81 canvas.setBitmap(canvas.getSubsetBitmap());
82 }
83
84 public void exitFunction(View view){
85 this.finish();
86 }
87 }
1 package com.jichun.view;
2
3 import android.content.Context;
4 import android.graphics.Bitmap;
5 import android.graphics.Canvas;
6 import android.graphics.Color;
7 import android.graphics.Matrix;
8 import android.graphics.Paint;
9 import android.graphics.Rect;
10 import android.graphics.RectF;
11 import android.graphics.Bitmap.Config;
12 import android.graphics.drawable.BitmapDrawable;
13 import android.util.AttributeSet;
14 import android.view.MotionEvent;
15 import android.widget.ImageView;
16
17 public class CropCanvas extends ImageView {
18
19 private final static int PRESS_LB = 0;//表示左下角矩形框
20 private final static int PRESS_LT = 1;//表示左上角矩形框
21 private final static int PRESS_RB = 2;//表示右下角矩形框
22 private final static int PRESS_RT = 3;//表示右上角矩形框
23
24 private Bitmap bitMap = null; //原始图片
25 private RectF src = null; //经过比例转换后的裁剪区域
26 private RectF dst = null; //图片显示区域(可被裁剪的区域大小)
27 private RectF ChooseArea = null; //选择需要裁剪的区域
28 private Paint mPaint = null; //画笔
29 private Matrix matrix = null; //矩阵
30
31 private int mx = 0; //存储触笔移动时,之前所在的触笔的x坐标
32 private int my = 0; //存储触笔移动时,之前所在的触笔的y坐标
33 private boolean touchFlag = false; //触笔是否在屏幕之上
34 private boolean cutFlag = false; //是否点击了menu上的裁剪按钮
35 private int recFlag = -1; //用来存储触笔点击了哪个小矩形框(改变选择区域大小的小矩形框)
36 private boolean firstFlag = false;
37
38 private RectF recLT = null; //左上角的小矩形框
39 private RectF recRT = null; //右上角的小矩形框
40 private RectF recLB = null; //左下角的小矩形框
41 private RectF recRB = null; //右下角的小矩形框
42 private static final int LEFT_AREA_ALPHA = 50 * 255 / 100;
43 private RectF leftRectL = null;
44 private RectF leftRectR = null;
45 private RectF leftRectT = null;
46 private RectF leftRectB = null;
47 private Paint leftAreaPaint = null;
48
49 public CropCanvas(Context context, AttributeSet attrs) {
50 super(context, attrs);
51 this.init();
52 }
53
54 public CropCanvas(Context context) {
55 super(context);
56 this.init();
57 }
58
59 public void init(){
60 cutFlag = true;
61 recLT = new RectF();
62 recLB = new RectF();
63 recRT = new RectF();
64 recRB = new RectF();
65 dst = new RectF();
66 mPaint = new Paint();
67 mPaint.setColor(Color.RED);
68 mPaint.setStyle(Paint.Style.STROKE); //将画笔的风格改为空心
69 mPaint.setStrokeWidth(2);
70 ChooseArea = new RectF();
71 this.setPressRecLoc();
72 src = null;
73 firstFlag = true;
74
75 //选择框之外的灰色区域,分成四个矩形框
76
77 leftAreaPaint = new Paint();
78 leftAreaPaint.setStyle(Paint.Style.FILL);
79 leftAreaPaint.setAlpha(CropCanvas.LEFT_AREA_ALPHA);
80 }
81
82 public void setBitmap(Bitmap bitmap){
83 BitmapDrawable bd = new BitmapDrawable(bitmap);
84 src = new RectF(0,0,bd.getIntrinsicWidth(),bd.getIntrinsicHeight());
85 this.bitMap = bitmap.copy(Config.ARGB_8888, true);
86
87 this.setImageBitmap(bitMap);
88 leftRectB = new RectF();
89 leftRectL = new RectF();
90 leftRectR = new RectF();
91 leftRectT = new RectF();
92 }
93
94 public void imageScale(){
95 matrix = this.getImageMatrix();
96 matrix.mapRect(dst, src);
97 int padding = this.getPaddingBottom();
98 dst.set(dst.left+padding,dst.top+padding,dst.right+padding,dst.bottom+padding);
99 ChooseArea = new RectF(dst.left+40,dst.top+40,dst.right-40,dst.bottom-40);
100 this.setPressRecLoc();
101 this.invalidate();
102 }
103
104 //裁剪出选择区域里的图片
105 //之前要做比例转换,因为,你选择的区域是针对比例转换后的图片
106 //所以要使用ChooseArea的数值做比例转换,然后,使用这些数值重新设置rec的大小
107 public Bitmap getSubsetBitmap(){
108 float ratioWidth = bitMap.getWidth()/(float)(dst.right-dst.left);
109 float ratioHeight = bitMap.getHeight()/(float)(dst.bottom - dst.top);
110 int left = (int)((ChooseArea.left - dst.left) * ratioWidth);
111 int right = (int)(left + (ChooseArea.right - ChooseArea.left) * ratioWidth);
112 int top = (int)((ChooseArea.top - dst.top) * ratioHeight);
113 int bottom = (int)(top + (ChooseArea.bottom - ChooseArea.top) * ratioHeight);
114 src = new RectF(left,top,right,bottom);
115 firstFlag = true;
116 set_LeftArea_Alpha();
117 return Bitmap.createBitmap(bitMap, left, top, right-left, bottom-top);
118 }
119
120 //获得ChooseArea对象
121 public RectF getChooseArea(){
122 return ChooseArea;
123 }
124
125 //移动选择区域,选择区域是不能从图片区域里移出去的
126 public void moveChooseArea(int move_x,int move_y){
127 if(ChooseArea.left + move_x >= dst.left && ChooseArea.right + move_x <= dst.right
128 && ChooseArea.top + move_y >= dst.top && ChooseArea.bottom + move_y <= dst.bottom){
129 ChooseArea.set(ChooseArea.left + move_x,ChooseArea.top+move_y
130 ,ChooseArea.right + move_x,ChooseArea.bottom+move_y);
131 }else{
132 if(ChooseArea.left + move_x < dst.left){
133 ChooseArea.set(dst.left,ChooseArea.top
134 ,ChooseArea.right+dst.left-ChooseArea.left,ChooseArea.bottom);
135 }
136 if(ChooseArea.right + move_x > dst.right){
137 ChooseArea.set(ChooseArea.left+dst.right-ChooseArea.right,ChooseArea.top
138 ,dst.right,ChooseArea.bottom);
139 }
140
141 if(ChooseArea.top + move_y < dst.top){
142 ChooseArea.set(ChooseArea.left,dst.top
143 ,ChooseArea.right,ChooseArea.bottom+dst.top-ChooseArea.top);
144 }
145
146 if(ChooseArea.bottom + move_y > dst.bottom){
147 ChooseArea.set(ChooseArea.left,ChooseArea.top+dst.bottom-ChooseArea.bottom
148 ,ChooseArea.right,dst.bottom);
149 }
150 }
151 this.setPressRecLoc();
152 mPaint.setColor(Color.GREEN);
153 this.invalidate();
154 }
155
156 public boolean onTouchEvent(MotionEvent event){
157 mPaint.setColor(Color.RED);
158
159 //点击了裁剪按钮之后才会执行以下事件
160 if(event.getAction() == MotionEvent.ACTION_DOWN && cutFlag){
161 //System.out.println(event.getX() + "," + event.getY());
162 //判断触笔是否在裁剪区域内,也就是ChooseArea内
163 //如果是,整个区域随着鼠标移动而移动
164 mx = (int)event.getX();
165 my = (int)event.getY();
166 if(this.judgeLocation(mx,my)){
167 touchFlag = true;
168 mPaint.setColor(Color.GREEN);
169 this.invalidate();
170 return true;
171 }else{
172 //不在裁剪区域内,就判断触笔是否在改变区域大小的小矩形框之内
173 if(this.findPresseddst((int)event.getX(), (int)event.getY())){
174 touchFlag = true;
175 mPaint.setColor(Color.RED);
176 return true;
177 }
178 }
179 }
180
181 if(event.getAction() == MotionEvent.ACTION_MOVE && touchFlag){
182 //判断是否点击了哪个个小矩形框
183 if(this.isOutOfArea((int)event.getX(), (int)event.getY())){
184 return true;
185 }
186
187 //如果选择区域大小跟图像大小一样时,就不能移动
188 if(ChooseArea.left == dst.left && ChooseArea.top == dst.top &&
189 ChooseArea.right == dst.right && ChooseArea.bottom == dst.bottom){
190 }else{
191 this.moveChooseArea((int)event.getX() - mx, (int)event.getY() - my);
192 mx = (int)event.getX();
193 my = (int)event.getY();
194 }
195 }
196
197 //触笔移出屏幕时,将一些变量设回初值
198 if(event.getAction() == MotionEvent.ACTION_UP){
199 recFlag = -1;
200 this.invalidate();
201 touchFlag = false;
202 }
203
204 return super.onTouchEvent(event);
205 }
206
207
208
209 //判断是否要超出图片区域,这个函数会调用下面四个press打头的函数
210 //这个函数也会重绘整个画布,也就是选择区域会随着鼠标的移动改变
211 private boolean isOutOfArea(int x,int y){
212 switch(recFlag){
213 case CropCanvas.PRESS_LB:
214 this.pressLB(x - mx, y - my);
215 break;
216 case CropCanvas.PRESS_LT:
217 this.pressLT(x - mx, y - my);
218 break;
219 case CropCanvas.PRESS_RB:
220 this.pressRB(x - mx, y - my);
221 break;
222 case CropCanvas.PRESS_RT:
223 this.pressRT(x - mx, y - my);
224 break;
225 default:return false;
226 }
227 mx = x;
228 my = y;
229 this.invalidate();
230 return true;
231 }
232
233 //找到点击了哪个矩形框(改变选择区域大小的小矩形框)
234 //这个是在MotionEvent.ACTION_DOWN这个动作时执行的
235 //是为了在MotionEvent.ACTION_MOVE的时候,知道应该移动哪个小矩形框
236 public boolean findPresseddst(int x,int y){
237 boolean returnFlag = false;
238 if(this.isInRect(x, y, recLB)){
239 recFlag = CropCanvas.PRESS_LB;
240 returnFlag = true;
241 }else if(this.isInRect(x, y, recLT)){
242 recFlag = CropCanvas.PRESS_LT;
243 returnFlag = true;
244 }else if(this.isInRect(x, y, recRB)){
245 recFlag = CropCanvas.PRESS_RB;
246 returnFlag = true;
247 }else if(this.isInRect(x, y, recRT)){
248 recFlag = CropCanvas.PRESS_RT;
249 returnFlag = true;
250 }
251
252 return returnFlag;
253 }
254
255 public boolean isInRect(int x,int y,RectF rect){
256 if(x >= rect.left -20 && x <= rect.right + 20 && y > rect.top - 20 && y < rect.bottom + 20){
257 return true;
258 }
259 return false;
260 }
261
262 //点击角落矩形框改变选择区域大小时,不能超过图片所在的区域
263 //下面以press打头的四个函数就是判断是否超出图片区域
264 //如果超出了,就移动不了
265 //不超出按照触笔移动的距离来移动小矩形框
266
267 //pressLB是当点击左下角小矩形框改变大小时是否超出图片区域
268 //如果超出就将left与bottom的值设为图片区域的left和bottom
269 private void pressLB(int x,int y){
270 float left = ChooseArea.left + x;
271 float right = ChooseArea.right;
272 float top = ChooseArea.top;
273 float bottom = ChooseArea.bottom + y;
274 if(left <= right - 30 && left >= dst.left && bottom <= dst.bottom && bottom >= top + 30){
275 ChooseArea.set(left,top,right,bottom);
276 }else{
277 if(left + x < dst.left){
278 left = dst.left;
279 }
280
281 if(bottom + y > dst.bottom){
282 bottom = dst.bottom;
283 }
284
285 if(ChooseArea.left + x > ChooseArea.right - 30){
286 left = ChooseArea.right - 30;
287 }
288
289 if(ChooseArea.bottom + y < ChooseArea.top + 30){
290 bottom = ChooseArea.top + 30;
291 }
292 ChooseArea.set(left,top,right,bottom);
293 }
294 this.setPressRecLoc();
295 }
296
297 //pressLT是当点击左上角小矩形框改变大小时是否超出图片区域
298 //如果超出就将left与top的值设为图片区域的left和top
299 private void pressLT(int x,int y){
300 float left = ChooseArea.left + x;
301 float right = ChooseArea.right;
302 float top = ChooseArea.top + y;
303 float bottom = ChooseArea.bottom;
304 if(left <= right - 30 && left >= dst.left && top <= bottom - 30 && top >= dst.top){
305 ChooseArea.set(left,top,right,bottom);
306 }else{
307 if(left < dst.left){
308 left = dst.left;
309 }
310
311 if(top < dst.top){
312 top = dst.top;
313 }
314
315 if(left > right - 30){
316 left = right - 30;
317 }
318
319 if(top > bottom - 30){
320 top = bottom - 30;
321 }
322 ChooseArea.set(left,top,right,bottom);
323 }
324 this.setPressRecLoc();
325 }
326
327 //pressRT是当点击右上角小矩形框改变大小时是否超出图片区域
328 //如果超出就将right与top的值设为图片区域的right和top
329 private void pressRT(int x,int y){
330 float left = ChooseArea.left;
331 float right = ChooseArea.right + x;
332 float top = ChooseArea.top + y;
333 float bottom = ChooseArea.bottom;
334
335 if(right <= dst.right && right >= left + 30 && top <= bottom - 30 && top >= dst.top){
336 ChooseArea.set(left,top,right,bottom);
337 }else{
338 if(right > dst.right){
339 right = dst.right;
340 }
341
342 if(top < dst.top){
343 top = dst.top;
344 }
345
346 if(right < left + 30){
347 right = left + 30;
348 }
349
350 if(top > bottom - 30){
351 top = bottom - 30;
352 }
353 ChooseArea.set(left,top,right,bottom);
354 }
355 this.setPressRecLoc();
356 }
357
358 //pressRB是当点击右下角小矩形框改变大小时是否超出图片区域
359 //如果超出就将right与bottom的值设为图片区域的right和bottom
360 private void pressRB(int x,int y){
361 float left = ChooseArea.left;
362 float right = ChooseArea.right + x;
363 float top = ChooseArea.top;
364 float bottom = ChooseArea.bottom + y;
365
366 if(right<= dst.right && right >= left + 30 && bottom <= dst.bottom && bottom >= top + 30){
367 ChooseArea.set(left,top,right,bottom);
368 }else{
369 if(right > dst.right){
370 right = dst.right;
371 }
372
373 if(bottom > dst.bottom){
374 bottom = dst.bottom;
375 }
376
377 if(right < left + 30){
378 right = left + 30;
379 }
380
381 if(bottom < top + 30){
382 bottom = top + 30;
383 }
384 ChooseArea.set(left,top,right,bottom);
385 }
386 this.setPressRecLoc();
387 }
388
389 //每次改变选择区域矩形的大小或者移动,各角落上的小矩形也要改变它的Location
390 private void setPressRecLoc(){
391 recLT.set(ChooseArea.left-8,ChooseArea.top-8 , ChooseArea.left+8, ChooseArea.top+8);
392 recLB.set(ChooseArea.left-8,ChooseArea.bottom-8 , ChooseArea.left+8, ChooseArea.bottom+8);
393 recRT.set(ChooseArea.right-8,ChooseArea.top-8 , ChooseArea.right+8, ChooseArea.top+8);
394 recRB.set(ChooseArea.right-8,ChooseArea.bottom-8 , ChooseArea.right+8, ChooseArea.bottom+8);
395 }
396
397 //判断触笔是否在选择区域内
398 public boolean judgeLocation(float x,float y){
399 float start_x = this.getChooseArea().left;
400 float start_y = this.getChooseArea().top;
401 float last_x = this.getChooseArea().right;
402 float last_y = this.getChooseArea().bottom;
403 //System.out.println("chubi:" + x + "," + y);
404 //System.out.println(start_y + "," + last_y);
405 if(x > start_x+10 && x < last_x-10 && y > start_y+10 && y < last_y-10){
406 return true;
407 }
408 return false;
409 }
410
411 public void onDraw(Canvas canvas){
412 super.onDraw(canvas);
413 if(firstFlag){
414 this.imageScale();
415 firstFlag = false;
416 mPaint.setColor(Color.RED);
417 System.out.println("Width: " + (dst.right - dst.left));
418 System.out.println("Height: " + (dst.bottom - dst.top));
419 System.out.println("Width: " + this.getDrawable().getIntrinsicWidth());
420 System.out.println("Height: " + this.getDrawable().getIntrinsicHeight());
421 }else{
422 set_LeftArea_Alpha();
423 }
424 canvas.drawRect(ChooseArea, mPaint);
425 mPaint.setColor(Color.BLUE);
426 canvas.drawRect(recLT, mPaint);
427 canvas.drawRect(recLB, mPaint);
428 canvas.drawRect(recRT, mPaint);
429 canvas.drawRect(recRB, mPaint);
430
431 canvas.drawRect(leftRectL, leftAreaPaint);
432 canvas.drawRect(leftRectR, leftAreaPaint);
433 canvas.drawRect(leftRectT, leftAreaPaint);
434 canvas.drawRect(leftRectB, leftAreaPaint);
435
436 }
437
438 public void set_LeftArea_Alpha(){
439 leftRectL.set(dst.left, dst.top, ChooseArea.left, dst.bottom);
440 leftRectR.set(ChooseArea.right,dst.top,dst.right,dst.bottom);
441 leftRectT.set(ChooseArea.left, dst.top, ChooseArea.right, ChooseArea.top);
442 leftRectB.set(ChooseArea.left,ChooseArea.bottom,ChooseArea.right,dst.bottom);
443 }
444 }
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="150px"
android:layout_alignParentTop="true"
android:layout_weight="1"
android:background="#191919"
android:orientation="horizontal" >
</LinearLayout>
<com.jichun.view.CropCanvas
android:id="@+id/myCanvas"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="5px"
android:layout_marginTop="5px"
android:layout_weight="1"
android:background="#313131"
android:padding="2dip" >
</com.jichun.view.CropCanvas>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="150px"
android:layout_weight="1"
android:background="#191919" >
<ImageButton
android:id="@+id/confirm_button"
android:layout_width="70px"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:background="#00000000"
android:src="@drawable/confirmxml" >
</ImageButton>
<ImageButton
android:id="@+id/exit_button"
android:layout_width="70px"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:background="#00000000"
android:src="@drawable/exitxml" >
</ImageButton>
</RelativeLayout>
</LinearLayout>
1 <?xml version="1.0" encoding="utf-8" ?>
2 <selector xmlns:android="http://schemas.android.com/apk/res/android">
3 <item android:state_window_focused="false"
4 android:drawable="@drawable/confirm" />
5
6 <item android:state_focused="true" android:state_pressed="true"
7 android:drawable="@drawable/confirm_focus" />
8 <item android:state_focused="false" android:state_pressed="true"
9 android:drawable="@drawable/confirm_focus" />
10
11 <item android:state_focused="true"
12 android:drawable="@drawable/confirm_focus" />
13 </selector>
完整项目下载链接:http://pan.baidu.com/s/1c08a4Re