南尘 阅读(261) 评论(0)

最近在做毕业设计,想有一个功能和QQ一样可以裁剪头像并设置圆形头像,额,这是设计狮的一种潮流。

而纵观现在主流的APP,只要有用户系统这个功能,这个需求一般都是在(bu)劫(de)难(bu)逃(xue)!

图片裁剪实现方式有两种,一种是利用系统自带的裁剪工具,一种是使用开源工具Cropper。本节就为大家带来如何使用系统自带的裁剪工具进行图片裁剪~

还是先来个简单的运行图。(Ps,本人还没结婚,照片是我表哥~)

 

额,简单说下,我待会会把代码写成小demo分享给大家,在文章末尾会附上github链接,需要的可以自行下载~

 

 

下面来简单分析一下实现思路,我们首先照片肯定可以通过拍照和从相册选取,这个都可以向系统发送特定的Intent,响应对应的系统程序,然后在onActivityResult里面,获取我们的数据即可。而在onActivityResult里面,我们可以获取到两种形式的数据,Bitmap and uri。一般情况下我们是不会选择Bitmap的,因为大家都知道我们的手机里面的照片都太大了~强行使用bitmap,我只能说你,屌屌屌,sorry,我说的不是666,是傻屌的意思!

 

哈哈哈,让我爆粗口,我原本是拒绝的~只是希望警醒在看文章的你,那么就用uri吧~

 

那么然后呢?当然是对它做裁剪,完成后把这个裁剪后的bitmap对象设置给ImageView,保存起来,上传到服务器即可。

大致了解了流程,那么我们直接看代码吧~

先看看我们的圆形Image吧,我这个有点乱,因为考虑了很多我毕设的逻辑,所以做了一些修正,这个圆形Image相信网上会很多。

  1 package com.example.nanchen.cropimagetest;
  2 
  3 import android.content.Context;
  4 import android.content.res.TypedArray;
  5 import android.graphics.Bitmap;
  6 import android.graphics.Bitmap.Config;
  7 import android.graphics.Canvas;
  8 import android.graphics.Color;
  9 import android.graphics.ColorMatrix;
 10 import android.graphics.ColorMatrixColorFilter;
 11 import android.graphics.Paint;
 12 import android.graphics.PorterDuff.Mode;
 13 import android.graphics.PorterDuffXfermode;
 14 import android.graphics.Rect;
 15 import android.graphics.RectF;
 16 import android.util.AttributeSet;
 17 import android.view.MotionEvent;
 18 import android.view.View;
 19 import android.widget.ImageView;
 20 
 21 /**
 22  * @author nanchen
 23  * @fileName CropImageTest
 24  * @packageName com.example.nanchen.cropimagetest
 25  * @date 2016/10/13  15:09
 26  */
 27 
 28 public class RoundImageView extends ImageView {
 29 
 30     /**
 31      * 圆形ImageView,可设置最多两个宽度不同且颜色不同的圆形边框。
 32      *
 33      * @author Alan
 34      */
 35 
 36     private static class imageview_level {
 37         public final static int level0 = 0;
 38         public final static int level1 = 1;
 39         public final static int level2 = 2;
 40         public final static int level3 = 3;
 41         public final static int level4 = 4;
 42     }
 43 
 44 
 45     private Context mContext;
 46     private int circleColor = Color.WHITE;
 47     private int circleWidth = 0;
 48     private int mLevel = imageview_level.level1;
 49 
 50     public void setLevel(int level) {
 51         mLevel = level;
 52     }
 53     public RoundImageView(Context context) {
 54         super(context);
 55         mContext = context;
 56     }
 57 
 58     public RoundImageView(Context context, AttributeSet attrs) {
 59         super(context, attrs);
 60         mContext = context;
 61         setCustomAttributes(attrs);
 62     }
 63 
 64     public RoundImageView(Context context, AttributeSet attrs, int defStyle) {
 65         super(context, attrs, defStyle);
 66         mContext = context;
 67         setCustomAttributes(attrs);
 68     }
 69 
 70     private void setCustomAttributes(AttributeSet attrs) {
 71         TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.roundedimageview);
 72         int width = a.getDimensionPixelSize(R.styleable.roundedimageview_border_thickness, 0);
 73         setPadding(width, width, width, width);
 74         mLevel = a.getInt(R.styleable.roundedimageview_image_mode, imageview_level.level1);
 75         circleColor = a.getColor(R.styleable.roundedimageview_border_color, circleColor);
 76     }
 77 
 78 
 79     @Override
 80     public void setImageBitmap(Bitmap bm) {
 81         switch (this.mLevel) {
 82             case imageview_level.level1 :
 83                 bm = RoundBitmap(bm);
 84             case imageview_level.level2 :
 85                 if ((getPaddingLeft() == getPaddingRight()) && (getPaddingLeft() == getPaddingBottom())
 86                         && (getPaddingLeft() == getPaddingTop())) {
 87                     this.circleWidth = getPaddingLeft();
 88                     bm = RoundBitmap(bm);
 89                 }
 90                 break;
 91             case imageview_level.level3 :
 92                 bm = ChamferBitmap(bm);
 93                 break;
 94             case imageview_level.level4:
 95                 if ((getPaddingLeft() == getPaddingRight()) && (getPaddingLeft() == getPaddingBottom())
 96                         && (getPaddingLeft() == getPaddingTop())) {
 97                     this.circleWidth = getPaddingLeft();
 98                     bm = RoundBitmap(bm);
 99                 }
100                 break;
101             default :
102                 break;
103         }
104         super.setImageBitmap(bm);
105     }
106 
107     @Override
108     protected void onDraw(Canvas canvas) {
109         switch (this.mLevel) {
110             case imageview_level.level2:
111                 if (circleWidth > 0) {
112                     drawCircleBorder(canvas, (getWidth() - this.circleWidth*2 + circleWidth) / 2, this.circleColor, getWidth(),
113                             getHeight(), this.circleWidth);
114                 }
115                 break;
116             case imageview_level.level4:
117                 if (circleWidth > 0){
118                     int paddingwidth = circleWidth;
119 
120                     drawCircleBorder(canvas, (getWidth()-paddingwidth*2 +circleWidth /2) / 2, this.circleColor, getWidth(),
121                             getHeight(), this.circleWidth /2,Color.DKGRAY);
122 
123                     int tempwidth = circleWidth /2;
124                     drawCircleBorder(canvas, (getWidth()-paddingwidth*2 +tempwidth) / 2, this.circleColor, getWidth(),
125                             getHeight(), tempwidth,Color.DKGRAY);
126 
127                 }
128                 break;
129             default:
130                 break;
131         }
132         super.onDraw(canvas);
133     }
134 
135     /**
136      * bitmap切成圆形
137      *
138      * @param bitmap 传入Bitmap对象
139      * @return
140      */
141     private Bitmap RoundBitmap(Bitmap bitmap) {
142         Bitmap resultBitmap = null;
143         Canvas canvas = null;
144         int width = bitmap.getWidth();
145         int height = bitmap.getHeight();
146         float roundPx;
147         float left, top, right, bottom, dst_left, dst_top, dst_right, dst_bottom;
148         if (width <= height) {
149             roundPx = width / 2;
150             top = 0;
151             bottom = width;
152             left = 0;
153             right = width;
154             height = width;
155             dst_left = 0;
156             dst_top = 0;
157             dst_right = width;
158             dst_bottom = width;
159         } else {
160             roundPx = height / 2;
161             float clip = (width - height) / 2;
162             left = clip;
163             right = width - clip;
164             top = 0;
165             bottom = height;
166             width = height;
167             dst_left = 0;
168             dst_top = 0;
169             dst_right = height;
170             dst_bottom = height;
171         }
172         if (width <= 0) {
173             width = 1;
174         }
175         if (height <= 0) {
176             height = 1;
177         }
178 
179         try {
180             resultBitmap = Bitmap.createBitmap(width, height, Config.ARGB_4444);
181         } catch (Throwable e) {
182             e.printStackTrace();
183         }
184 
185         try {
186             canvas = new Canvas(resultBitmap);
187         } catch (Throwable e) {
188             e.printStackTrace();
189         }
190 
191         final int color = Color.RED;
192         final Paint paint = new Paint();
193         final Rect src = new Rect((int) left, (int) top, (int) right, (int) bottom);
194         final Rect dst = new Rect((int) dst_left, (int) dst_top, (int) dst_right, (int) dst_bottom);
195         final RectF rectF = new RectF(dst);
196         paint.setAntiAlias(true);
197         canvas.drawARGB(0, 0, 0, 0);
198         // paint.setColor(color);
199         canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
200         paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
201         canvas.drawBitmap(bitmap, src, dst, paint);
202         return resultBitmap;
203     }
204 
205     /**
206      * bitmap倒角
207      *
208      * @param bitmap 传入Bitmap对象
209      * @return
210      */
211     private Bitmap ChamferBitmap(Bitmap bitmap) {
212         Bitmap resultBitmap = null;
213         Canvas canvas = null;
214         int width = bitmap.getWidth();
215         int height = bitmap.getHeight();
216         float roundPx;
217         float left, top, right, bottom, dst_left, dst_top, dst_right, dst_bottom;
218         if (width <= height) {
219             roundPx = dip2px(this.mContext, 4); // 8像素倒角 4是dp值
220             top = 0;
221             bottom = width;
222             left = 0;
223             right = width;
224             height = width;
225             dst_left = 0;
226             dst_top = 0;
227             dst_right = width;
228             dst_bottom = width;
229         } else {
230             roundPx = dip2px(this.mContext, 4); // 8像素倒角 4是dp值
231             float clip = (width - height) / 2;
232             left = clip;
233             right = width - clip;
234             top = 0;
235             bottom = height;
236             width = height;
237             dst_left = 0;
238             dst_top = 0;
239             dst_right = height;
240             dst_bottom = height;
241         }
242         if (width <= 0) {
243             width = 1;
244         }
245         if (height <= 0) {
246             height = 1;
247         }
248 
249         try {
250             resultBitmap = Bitmap.createBitmap(width, height, Config.ARGB_4444);
251         } catch (Throwable e) {
252             e.printStackTrace();
253         }
254 
255         try {
256             canvas = new Canvas(resultBitmap);
257         } catch (Throwable e) {
258             e.printStackTrace();
259         }
260 
261         final int color = Color.RED;
262         final Paint paint = new Paint();
263         final Rect src = new Rect((int) left, (int) top, (int) right, (int) bottom);
264         final Rect dst = new Rect((int) dst_left, (int) dst_top, (int) dst_right, (int) dst_bottom);
265         final RectF rectF = new RectF(dst);
266         paint.setAntiAlias(true);
267         canvas.drawARGB(0, 0, 0, 0);
268         // paint.setColor(color);
269         canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
270         paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
271         canvas.drawBitmap(bitmap, src, dst, paint);
272         return resultBitmap;
273     }
274 
275     /**
276      * 画布画圆
277      */
278     private void drawCircleBorder(Canvas canvas, int radius, int color, int width, int height, int circleWidth) {
279         Paint paint = new Paint();
280         /* 去锯齿 */
281         paint.setAntiAlias(true);
282         paint.setFilterBitmap(true);
283         paint.setDither(true);
284         paint.setColor(color);
285         /* 设置paint的 style 为STROKE:空心 */
286         paint.setStyle(Paint.Style.STROKE);
287         /* 设置paint的外框宽度 */
288         paint.setStrokeWidth(circleWidth);
289         canvas.drawCircle(width / 2, height / 2, radius, paint);
290     }
291 
292     private void drawCircleBorder(Canvas canvas, int radius, int color, int width, int height, int circleWidth,int shadowcolor){
293 
294         canvas.save();  //保存画布当前状态
295         canvas.rotate(45,width / 2, height / 2);  //右下角45度阴影投射
296         Paint paint = new Paint();
297         paint.setColor(0x09ffffff & shadowcolor ); //设置alpha值
298         for(int i=0;i<circleWidth*2;i++)  //向下角角偏移投射多少次阴影层
299         {
300             canvas.drawCircle(width/2+i, height / 2, radius+2, paint);
301         }
302         canvas.restore();
303 
304         paint = new Paint();
305         /* 去锯齿 */
306         paint.setAntiAlias(true);
307         paint.setFilterBitmap(true);
308         paint.setDither(true);
309         paint.setColor(color);
310         /* 设置paint的 style 为STROKE:空心 */
311         paint.setStyle(Paint.Style.STROKE);
312         /* 设置paint的外框宽度 */
313         paint.setStrokeWidth(circleWidth); //二分之一实体
314         canvas.drawCircle(width / 2, height / 2, radius, paint);
315     }
316 
317     public void setCircleWidth(int padding) {
318         setPadding(padding, padding, padding, padding);
319     }
320 
321     public int getCircleColor() {
322         return circleColor;
323     }
324 
325     public void setCircleColor(int circleColor) {
326         this.circleColor = circleColor;
327     }
328 
329     // 执行完setImageBitmap后才能获得;
330     public int getCircleWidth() {
331         return this.circleWidth;
332     }
333 
334     public OnTouchListener onTouchListener = new OnTouchListener() {
335         @Override
336         public boolean onTouch(View view, MotionEvent event) {
337             switch (event.getAction()) {
338                 case MotionEvent.ACTION_UP:
339                     changeLight((ImageView) view, 0);
340                     // onclick
341                     break;
342                 case MotionEvent.ACTION_DOWN:
343                     changeLight((ImageView) view, -60);
344                     break;
345                 case MotionEvent.ACTION_MOVE:
346 //                 changeLight((ImageView) view, 0);
347                     break;
348                 case MotionEvent.ACTION_CANCEL:
349                     changeLight((ImageView) view, 0);
350                     break;
351                 default:
352                     break;
353             }
354             return false;
355         }
356     };
357 
358     public void setColorFilter(boolean value){
359         if(value){
360             setOnTouchListener(onTouchListener);
361         }else{
362             setOnTouchListener(null);
363         }
364     }
365 
366     private void changeLight(ImageView imageview, int brightness) {
367         ColorMatrix matrix = new ColorMatrix();
368         matrix.set(new float[] { 1, 0, 0, 0, brightness, 0, 1, 0, 0, brightness, 0, 0, 1, 0, brightness, 0, 0, 0, 1, 0 });
369         imageview.setColorFilter(new ColorMatrixColorFilter(matrix));
370     }
371 
372     /**
373      * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
374      */
375     private int dip2px(Context context, float dpValue) {
376         final float scale = context.getApplicationContext().getResources().getDisplayMetrics().density;
377         return (int) (dpValue * scale + 0.5f);
378     }
379 
380 
381 }

 

自定义一个仿IOS的弹出框

  1 package com.example.nanchen.cropimagetest;
  2 
  3 import android.app.Activity;
  4 import android.app.Dialog;
  5 import android.os.Bundle;
  6 import android.text.TextUtils;
  7 import android.view.LayoutInflater;
  8 import android.view.View;
  9 import android.view.View.OnClickListener;
 10 import android.view.ViewGroup;
 11 import android.view.ViewGroup.LayoutParams;
 12 import android.view.Window;
 13 import android.view.WindowManager;
 14 import android.widget.AdapterView;
 15 import android.widget.AdapterView.OnItemClickListener;
 16 import android.widget.BaseAdapter;
 17 import android.widget.Button;
 18 import android.widget.ListView;
 19 import android.widget.TextView;
 20 
 21 import java.util.List;
 22 
 23 
 24 /**
 25  * dialog
 26  * 
 27  */
 28 public class SelectDialog extends Dialog implements OnClickListener,OnItemClickListener {
 29     private SelectDialogListener mListener;
 30     private Activity mActivity;
 31     private Button mMBtn_Cancel;
 32     private TextView mTv_Title;
 33     private List<String> mName;
 34     private String mTitle;
 35     private boolean mUseCustomColor = false;
 36     private int mFirstItemColor;
 37     private int mOtherItemColor;
 38     
 39     public interface SelectDialogListener {
 40         public void onItemClick(AdapterView<?> parent, View view, int position, long id);
 41     }
 42 
 43     
 44     private SelectDialogCancelListener mCancelListener;
 45     
 46     public interface SelectDialogCancelListener {
 47         public void onCancelClick(View v);
 48     }
 49 
 50     public SelectDialog(Activity activity, int theme,
 51             SelectDialogListener listener,List<String> names) {
 52         super(activity, theme);
 53         mActivity = activity;
 54         mListener = listener;
 55         this.mName=names;
 56         
 57         // 设置是否点击外围解散
 58         setCanceledOnTouchOutside(true);
 59     }
 60     
 61     /**
 62      * @param activity 调用弹出菜单的activity
 63      * @param theme 主题
 64      * @param listener 菜单项单击事件
 65      * @param cancelListener 取消事件
 66      * @param names 菜单项名称
 67      * 
 68      */
 69     public SelectDialog(Activity activity, int theme,SelectDialogListener listener,SelectDialogCancelListener cancelListener ,List<String> names) {
 70         super(activity, theme);
 71         mActivity = activity;
 72         mListener = listener;
 73         mCancelListener = cancelListener;
 74         this.mName=names;
 75         
 76         // 设置是否点击外围不解散
 77         setCanceledOnTouchOutside(false);
 78     }
 79     
 80     /**
 81      * @param activity 调用弹出菜单的activity
 82      * @param theme 主题
 83      * @param listener 菜单项单击事件
 84      * @param names 菜单项名称
 85      * @param title 菜单标题文字
 86      * 
 87      */
 88     public SelectDialog(Activity activity, int theme,SelectDialogListener listener,List<String> names,String title) {
 89         super(activity, theme);
 90         mActivity = activity;
 91         mListener = listener;
 92         this.mName=names;
 93         mTitle = title;
 94         
 95         // 设置是否点击外围可解散
 96         setCanceledOnTouchOutside(true);
 97     }
 98 
 99     public SelectDialog(Activity activity, int theme,SelectDialogListener listener,SelectDialogCancelListener cancelListener,List<String> names,String title) {
100         super(activity, theme);
101         mActivity = activity;
102         mListener = listener;
103         mCancelListener = cancelListener;
104         this.mName=names;
105         mTitle = title;
106         
107         // 设置是否点击外围可解散
108         setCanceledOnTouchOutside(true);
109     }
110 
111     @Override
112     protected void onCreate(Bundle savedInstanceState) {
113         super.onCreate(savedInstanceState);
114         View view = getLayoutInflater().inflate(R.layout.view_dialog_select,
115                 null);
116         setContentView(view, new LayoutParams(LayoutParams.FILL_PARENT,
117                 LayoutParams.WRAP_CONTENT));
118         Window window = getWindow();
119         // 设置显示动画
120         window.setWindowAnimations(R.style.main_menu_animstyle);
121         WindowManager.LayoutParams wl = window.getAttributes();
122         wl.x = 0;
123         wl.y = mActivity.getWindowManager().getDefaultDisplay().getHeight();
124         // 以下这两句是为了保证按钮可以水平满屏
125         wl.width = LayoutParams.MATCH_PARENT;
126         wl.height = LayoutParams.WRAP_CONTENT;
127 
128         // 设置显示位置
129         onWindowAttributesChanged(wl);
130         
131             //setCanceledOnTouchOutside(false);
132         initViews();
133     }
134 
135     private void initViews() {
136         DialogAdapter dialogAdapter=new DialogAdapter(mName);
137         ListView dialogList=(ListView) findViewById(R.id.dialog_list);
138         dialogList.setOnItemClickListener(this);
139         dialogList.setAdapter(dialogAdapter);
140         mMBtn_Cancel = (Button) findViewById(R.id.mBtn_Cancel);
141         mTv_Title = (TextView) findViewById(R.id.mTv_Title);
142         
143             //mMBtn_Cancel.setOnClickListener(this);
144 
145         mMBtn_Cancel.setOnClickListener(new View.OnClickListener() {
146             
147             @Override
148             public void onClick(View v) {
149                 // TODO Auto-generated method stub
150                 if(mCancelListener != null){
151                     mCancelListener.onCancelClick(v);    
152                 }
153                 dismiss();
154             }
155         });
156         
157         if(!TextUtils.isEmpty(mTitle) && mTv_Title != null){
158             mTv_Title.setVisibility(View.VISIBLE);
159             mTv_Title.setText(mTitle);
160         }else{
161             mTv_Title.setVisibility(View.GONE);
162         }
163     }
164 
165     @Override
166     public void onClick(View v) {
167         dismiss();
168 
169     }
170 
171     @Override
172     public void onItemClick(AdapterView<?> parent, View view, int position,
173             long id) {
174         
175         mListener.onItemClick(parent, view, position, id);
176         dismiss();
177     }
178     private class DialogAdapter extends BaseAdapter {
179         private List<String> mStrings;
180         private Viewholder viewholder;
181         private LayoutInflater layoutInflater;
182         public DialogAdapter(List<String> strings) {
183             this.mStrings = strings;
184             this.layoutInflater=mActivity.getLayoutInflater();
185         }
186 
187         @Override
188         public int getCount() {
189             // TODO Auto-generated method stub
190             return mStrings.size();
191         }
192 
193         @Override
194         public Object getItem(int position) {
195             // TODO Auto-generated method stub
196             return mStrings.get(position);
197         }
198 
199         @Override
200         public long getItemId(int position) {
201             // TODO Auto-generated method stub
202             return position;
203         }
204 
205         @Override
206         public View getView(int position, View convertView, ViewGroup parent) {
207             if (null == convertView) {
208                 viewholder=new Viewholder();
209                 convertView=layoutInflater.inflate(R.layout.view_dialog_item, null);
210                 viewholder.dialogItemButton=(TextView) convertView.findViewById(R.id.dialog_item_bt);
211                 convertView.setTag(viewholder);
212             }else{
213                 viewholder=(Viewholder) convertView.getTag();
214             }
215             viewholder.dialogItemButton.setText(mStrings.get(position));
216             if (!mUseCustomColor) {
217                 mFirstItemColor = mActivity.getResources().getColor(R.color.dialog_blue);
218                 mOtherItemColor = mActivity.getResources().getColor(R.color.dialog_blue);
219             }
220             if (1 == mStrings.size()) {
221                 viewholder.dialogItemButton.setTextColor(mFirstItemColor);
222                 viewholder.dialogItemButton.setBackgroundResource(R.drawable.dialog_item_bg_only);
223             } else if (position == 0) {
224                 viewholder.dialogItemButton.setTextColor(mFirstItemColor);
225                 viewholder.dialogItemButton.setBackgroundResource(R.drawable.dialog_item_bg_top);
226             } else if (position == mStrings.size() - 1) {
227                 viewholder.dialogItemButton.setTextColor(mOtherItemColor);
228                 viewholder.dialogItemButton.setBackgroundResource(R.drawable.dialog_item_bg_buttom);
229             } else {
230                 viewholder.dialogItemButton.setTextColor(mOtherItemColor);
231                 viewholder.dialogItemButton.setBackgroundResource(R.drawable.dialog_item_bg_center);
232             }
233             return convertView;
234         }
235 
236     }
237 
238     public static class Viewholder {
239         public TextView dialogItemButton;
240     }
241 
242     /**
243      * 设置列表项的文本颜色
244      */
245     public void setItemColor(int firstItemColor, int otherItemColor) {
246         mFirstItemColor = firstItemColor;
247         mOtherItemColor = otherItemColor;
248         mUseCustomColor = true;
249     }
250     
251 }

 

由于图片文件一定在相册中,有可能你也会在文件系统中其他地方选择,这里我采用之前写的万能适配器

 

由于楼主时间的确比较紧,所以代码都是直接copy上来的,有些地方没做完全优化还望大家见谅!

再看看Activity的代码和布局

  1 package com.example.nanchen.cropimagetest;
  2 
  3 import android.content.ComponentName;
  4 import android.content.DialogInterface;
  5 import android.content.DialogInterface.OnCancelListener;
  6 import android.content.Intent;
  7 import android.content.pm.ResolveInfo;
  8 import android.graphics.Bitmap;
  9 import android.graphics.Bitmap.CompressFormat;
 10 import android.net.Uri;
 11 import android.os.Bundle;
 12 import android.os.Environment;
 13 import android.provider.MediaStore;
 14 import android.provider.MediaStore.Images.Media;
 15 import android.support.v7.app.AlertDialog;
 16 import android.support.v7.app.AlertDialog.Builder;
 17 import android.support.v7.app.AppCompatActivity;
 18 import android.view.View;
 19 import android.widget.AdapterView;
 20 
 21 import com.example.nanchen.cropimagetest.SelectDialog.SelectDialogListener;
 22 
 23 import java.io.File;
 24 import java.io.FileOutputStream;
 25 import java.io.IOException;
 26 import java.util.ArrayList;
 27 import java.util.List;
 28 
 29 public class MainActivity extends AppCompatActivity {
 30 
 31     private RoundImageView mHeadImage;
 32 
 33     @Override
 34     protected void onCreate(Bundle savedInstanceState) {
 35         super.onCreate(savedInstanceState);
 36         setContentView(R.layout.activity_main);
 37 
 38         mHeadImage = (RoundImageView) findViewById(R.id.main_roundImage);
 39     }
 40 
 41     private final int PHOTO_PICKED_FROM_CAMERA = 1; // 用来标识头像来自系统拍照
 42     private final int PHOTO_PICKED_FROM_FILE = 2; // 用来标识从相册获取头像
 43     private final int CROP_FROM_CAMERA = 3;
 44 
 45     private void getIconFromPhoto(){
 46         Intent intent = new Intent(Intent.ACTION_GET_CONTENT, Media.EXTERNAL_CONTENT_URI);
 47         intent.setType("image/*");
 48         startActivityForResult(intent, PHOTO_PICKED_FROM_FILE);
 49     }
 50 
 51     private void selectPhoto() {
 52         List<String> list = new ArrayList<>();
 53         list.add("拍照");
 54         list.add("相册");
 55         showDialog(new SelectDialogListener() {
 56             @Override
 57             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
 58                 switch (position){
 59                     case 0:
 60                         getIconFromCamera();
 61                         break;
 62                     case 1:
 63                         getIconFromPhoto(); // 从系统相册获取
 64                         break;
 65                     default:
 66                         break;
 67                 }
 68             }
 69         },list);
 70 
 71     }
 72 
 73     private Uri imgUri; // 由于android手机的图片基本都会很大,所以建议用Uri,而不用Bitmap
 74 
 75     /**
 76      * 调用系统相机拍照
 77      */
 78     private void getIconFromCamera() {
 79         Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
 80         imgUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
 81                 "avatar_"+String.valueOf(System.currentTimeMillis())+".png"));
 82         intent.putExtra(MediaStore.EXTRA_OUTPUT,imgUri);
 83         startActivityForResult(intent,PHOTO_PICKED_FROM_CAMERA);
 84     }
 85 
 86     private SelectDialog showDialog(SelectDialogListener listener, List<String> list){
 87         SelectDialog dialog = new SelectDialog(this,
 88                 R.style.transparentFrameWindowStyle,listener,list);
 89             dialog.show();
 90         return dialog;
 91     }
 92 
 93 
 94     /**
 95      * 尝试裁剪图片
 96      */
 97     private void doCrop(){
 98         final ArrayList<CropOption> cropOptions = new ArrayList<>();
 99         final Intent intent = new Intent("com.android.camera.action.CROP");
100         intent.setType("image/*");
101         List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent,0);
102         int size = list.size();
103         if (size == 0){
104             UIUtil.showToast(this,"当前不支持裁剪图片!");
105             return;
106         }
107         intent.setData(imgUri);
108         intent.putExtra("outputX",300);
109         intent.putExtra("outputY",300);
110         intent.putExtra("aspectX",1);
111         intent.putExtra("aspectY",1);
112         intent.putExtra("scale",true);
113         intent.putExtra("return-data",true);
114 
115         // only one
116         if (size == 1){
117             Intent intent1 = new Intent(intent);
118             ResolveInfo res = list.get(0);
119             intent1.setComponent(new ComponentName(res.activityInfo.packageName,res.activityInfo.name));
120             startActivityForResult(intent1,CROP_FROM_CAMERA);
121         }else {
122             // 很多可支持裁剪的app
123             for (ResolveInfo res : list) {
124                 CropOption co = new CropOption();
125                 co.title = getPackageManager().getApplicationLabel(res.activityInfo.applicationInfo);
126                 co.icon = getPackageManager().getApplicationIcon(res.activityInfo.applicationInfo);
127                 co.appIntent = new Intent(intent);
128                 co.appIntent.setComponent(new ComponentName(res.activityInfo.packageName,res.activityInfo.name));
129                 cropOptions.add(co);
130             }
131 
132             CommonAdapter<CropOption> adapter = new CommonAdapter<CropOption>(this,cropOptions,R.layout.layout_crop_selector) {
133                 @Override
134                 public void convert(ViewHolder holder, CropOption item) {
135                     holder.setImageDrawable(R.id.iv_icon,item.icon);
136                     holder.setText(R.id.tv_name,item.title);
137                 }
138             };
139 
140             AlertDialog.Builder builder = new Builder(this);
141             builder.setTitle("choose a app");
142             builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
143                 @Override
144                 public void onClick(DialogInterface dialog, int which) {
145                     startActivityForResult(cropOptions.get(which).appIntent,CROP_FROM_CAMERA);
146                 }
147             });
148             builder.setOnCancelListener(new OnCancelListener() {
149                 @Override
150                 public void onCancel(DialogInterface dialog) {
151                     if (imgUri != null){
152                         getContentResolver().delete(imgUri,null,null);
153                         imgUri = null;
154                     }
155                 }
156             });
157             AlertDialog dialog = builder.create();
158             dialog.show();
159 
160         }
161     }
162 
163 
164     @Override
165     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
166         super.onActivityResult(requestCode, resultCode, data);
167         if (resultCode != RESULT_OK){
168             return;
169         }
170         switch (requestCode) {
171             case PHOTO_PICKED_FROM_CAMERA:
172                 doCrop();
173                 break;
174             case PHOTO_PICKED_FROM_FILE:
175                 imgUri = data.getData();
176                 doCrop();
177                 break;
178             case CROP_FROM_CAMERA:
179                 if (data != null){
180                     setCropImg(data);
181                 }
182                 break;
183             default:
184                 break;
185         }
186     }
187 
188     private void setCropImg(Intent picData){
189         Bundle bundle = picData.getExtras();
190         if (bundle != null){
191             Bitmap mBitmap = bundle.getParcelable("data");
192             mHeadImage.setImageBitmap(mBitmap);
193             saveBitmap(Environment.getExternalStorageDirectory() + "/crop_"
194                     +System.currentTimeMillis() + ".png",mBitmap);
195         }
196     }
197 
198     private void saveBitmap(String fileName,Bitmap bitmap){
199         File file = new File(fileName);
200         FileOutputStream fout = null;
201         try {
202             file.createNewFile();
203             fout = new FileOutputStream(file);
204             bitmap.compress(CompressFormat.PNG,100,fout);
205             fout.flush();
206         } catch (IOException e) {
207             e.printStackTrace();
208         } finally {
209             try {
210                 if (fout!=null){
211                     fout.close();
212                 }
213                 UIUtil.showToast(MainActivity.this,"保存成功!");
214             } catch (IOException e) {
215                 e.printStackTrace();
216             }
217         }
218     }
219 
220     public void btnClick(View view) {
221         selectPhoto();
222     }
223 }

 

布局:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:id="@+id/activity_main"
 6     android:layout_width="match_parent"
 7     android:layout_height="match_parent"
 8     tools:context="com.example.nanchen.cropimagetest.MainActivity">
 9 
10 
11     <com.example.nanchen.cropimagetest.RoundImageView
12         android:id="@+id/main_roundImage"
13         android:layout_width="100dp"
14         android:layout_height="100dp"
15         android:layout_alignParentTop="true"
16         android:layout_centerInParent="true"
17         android:src="@drawable/default_avatar"/>
18 
19     <Button
20         android:id="@+id/main_btn"
21         android:layout_width="match_parent"
22         android:layout_height="wrap_content"
23         android:layout_below="@+id/main_roundImage"
24         android:onClick="btnClick"
25         android:text="设置头像"/>
26 </RelativeLayout>

 

 

最后,再次对大家表示歉意,代码有些地方讲解不是很到位,后面我把毕设完全做出来后也会开源给大家,供大家一起交流使用,请持续关注~