不多说,直接上代码(裁剪的代码摘自网络。)(项目可运行)

主要是系统自身的剪切方式在有些机型上会程序崩溃的问题。

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