最近在做毕业设计,想有一个功能和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相信网上会很多。

 package com.example.nanchen.cropimagetest;

 import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView; /**
* @author nanchen
* @fileName CropImageTest
* @packageName com.example.nanchen.cropimagetest
* @date 2016/10/13 15:09
*/ public class RoundImageView extends ImageView { /**
* 圆形ImageView,可设置最多两个宽度不同且颜色不同的圆形边框。
*
* @author Alan
*/ private static class imageview_level {
public final static int level0 = 0;
public final static int level1 = 1;
public final static int level2 = 2;
public final static int level3 = 3;
public final static int level4 = 4;
} private Context mContext;
private int circleColor = Color.WHITE;
private int circleWidth = 0;
private int mLevel = imageview_level.level1; public void setLevel(int level) {
mLevel = level;
}
public RoundImageView(Context context) {
super(context);
mContext = context;
} public RoundImageView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setCustomAttributes(attrs);
} public RoundImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
setCustomAttributes(attrs);
} private void setCustomAttributes(AttributeSet attrs) {
TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.roundedimageview);
int width = a.getDimensionPixelSize(R.styleable.roundedimageview_border_thickness, 0);
setPadding(width, width, width, width);
mLevel = a.getInt(R.styleable.roundedimageview_image_mode, imageview_level.level1);
circleColor = a.getColor(R.styleable.roundedimageview_border_color, circleColor);
} @Override
public void setImageBitmap(Bitmap bm) {
switch (this.mLevel) {
case imageview_level.level1 :
bm = RoundBitmap(bm);
case imageview_level.level2 :
if ((getPaddingLeft() == getPaddingRight()) && (getPaddingLeft() == getPaddingBottom())
&& (getPaddingLeft() == getPaddingTop())) {
this.circleWidth = getPaddingLeft();
bm = RoundBitmap(bm);
}
break;
case imageview_level.level3 :
bm = ChamferBitmap(bm);
break;
case imageview_level.level4:
if ((getPaddingLeft() == getPaddingRight()) && (getPaddingLeft() == getPaddingBottom())
&& (getPaddingLeft() == getPaddingTop())) {
this.circleWidth = getPaddingLeft();
bm = RoundBitmap(bm);
}
break;
default :
break;
}
super.setImageBitmap(bm);
} @Override
protected void onDraw(Canvas canvas) {
switch (this.mLevel) {
case imageview_level.level2:
if (circleWidth > 0) {
drawCircleBorder(canvas, (getWidth() - this.circleWidth*2 + circleWidth) / 2, this.circleColor, getWidth(),
getHeight(), this.circleWidth);
}
break;
case imageview_level.level4:
if (circleWidth > 0){
int paddingwidth = circleWidth; drawCircleBorder(canvas, (getWidth()-paddingwidth*2 +circleWidth /2) / 2, this.circleColor, getWidth(),
getHeight(), this.circleWidth /2,Color.DKGRAY); int tempwidth = circleWidth /2;
drawCircleBorder(canvas, (getWidth()-paddingwidth*2 +tempwidth) / 2, this.circleColor, getWidth(),
getHeight(), tempwidth,Color.DKGRAY); }
break;
default:
break;
}
super.onDraw(canvas);
} /**
* bitmap切成圆形
*
* @param bitmap 传入Bitmap对象
* @return
*/
private Bitmap RoundBitmap(Bitmap bitmap) {
Bitmap resultBitmap = null;
Canvas canvas = null;
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float roundPx;
float left, top, right, bottom, dst_left, dst_top, dst_right, dst_bottom;
if (width <= height) {
roundPx = width / 2;
top = 0;
bottom = width;
left = 0;
right = width;
height = width;
dst_left = 0;
dst_top = 0;
dst_right = width;
dst_bottom = width;
} else {
roundPx = height / 2;
float clip = (width - height) / 2;
left = clip;
right = width - clip;
top = 0;
bottom = height;
width = height;
dst_left = 0;
dst_top = 0;
dst_right = height;
dst_bottom = height;
}
if (width <= 0) {
width = 1;
}
if (height <= 0) {
height = 1;
} try {
resultBitmap = Bitmap.createBitmap(width, height, Config.ARGB_4444);
} catch (Throwable e) {
e.printStackTrace();
} try {
canvas = new Canvas(resultBitmap);
} catch (Throwable e) {
e.printStackTrace();
} final int color = Color.RED;
final Paint paint = new Paint();
final Rect src = new Rect((int) left, (int) top, (int) right, (int) bottom);
final Rect dst = new Rect((int) dst_left, (int) dst_top, (int) dst_right, (int) dst_bottom);
final RectF rectF = new RectF(dst);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
// paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, src, dst, paint);
return resultBitmap;
} /**
* bitmap倒角
*
* @param bitmap 传入Bitmap对象
* @return
*/
private Bitmap ChamferBitmap(Bitmap bitmap) {
Bitmap resultBitmap = null;
Canvas canvas = null;
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float roundPx;
float left, top, right, bottom, dst_left, dst_top, dst_right, dst_bottom;
if (width <= height) {
roundPx = dip2px(this.mContext, 4); // 8像素倒角 4是dp值
top = 0;
bottom = width;
left = 0;
right = width;
height = width;
dst_left = 0;
dst_top = 0;
dst_right = width;
dst_bottom = width;
} else {
roundPx = dip2px(this.mContext, 4); // 8像素倒角 4是dp值
float clip = (width - height) / 2;
left = clip;
right = width - clip;
top = 0;
bottom = height;
width = height;
dst_left = 0;
dst_top = 0;
dst_right = height;
dst_bottom = height;
}
if (width <= 0) {
width = 1;
}
if (height <= 0) {
height = 1;
} try {
resultBitmap = Bitmap.createBitmap(width, height, Config.ARGB_4444);
} catch (Throwable e) {
e.printStackTrace();
} try {
canvas = new Canvas(resultBitmap);
} catch (Throwable e) {
e.printStackTrace();
} final int color = Color.RED;
final Paint paint = new Paint();
final Rect src = new Rect((int) left, (int) top, (int) right, (int) bottom);
final Rect dst = new Rect((int) dst_left, (int) dst_top, (int) dst_right, (int) dst_bottom);
final RectF rectF = new RectF(dst);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
// paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, src, dst, paint);
return resultBitmap;
} /**
* 画布画圆
*/
private void drawCircleBorder(Canvas canvas, int radius, int color, int width, int height, int circleWidth) {
Paint paint = new Paint();
/* 去锯齿 */
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
paint.setColor(color);
/* 设置paint的 style 为STROKE:空心 */
paint.setStyle(Paint.Style.STROKE);
/* 设置paint的外框宽度 */
paint.setStrokeWidth(circleWidth);
canvas.drawCircle(width / 2, height / 2, radius, paint);
} private void drawCircleBorder(Canvas canvas, int radius, int color, int width, int height, int circleWidth,int shadowcolor){ canvas.save(); //保存画布当前状态
canvas.rotate(45,width / 2, height / 2); //右下角45度阴影投射
Paint paint = new Paint();
paint.setColor(0x09ffffff & shadowcolor ); //设置alpha值
for(int i=0;i<circleWidth*2;i++) //向下角角偏移投射多少次阴影层
{
canvas.drawCircle(width/2+i, height / 2, radius+2, paint);
}
canvas.restore(); paint = new Paint();
/* 去锯齿 */
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
paint.setColor(color);
/* 设置paint的 style 为STROKE:空心 */
paint.setStyle(Paint.Style.STROKE);
/* 设置paint的外框宽度 */
paint.setStrokeWidth(circleWidth); //二分之一实体
canvas.drawCircle(width / 2, height / 2, radius, paint);
} public void setCircleWidth(int padding) {
setPadding(padding, padding, padding, padding);
} public int getCircleColor() {
return circleColor;
} public void setCircleColor(int circleColor) {
this.circleColor = circleColor;
} // 执行完setImageBitmap后才能获得;
public int getCircleWidth() {
return this.circleWidth;
} public OnTouchListener onTouchListener = new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
changeLight((ImageView) view, 0);
// onclick
break;
case MotionEvent.ACTION_DOWN:
changeLight((ImageView) view, -60);
break;
case MotionEvent.ACTION_MOVE:
// changeLight((ImageView) view, 0);
break;
case MotionEvent.ACTION_CANCEL:
changeLight((ImageView) view, 0);
break;
default:
break;
}
return false;
}
}; public void setColorFilter(boolean value){
if(value){
setOnTouchListener(onTouchListener);
}else{
setOnTouchListener(null);
}
} private void changeLight(ImageView imageview, int brightness) {
ColorMatrix matrix = new ColorMatrix();
matrix.set(new float[] { 1, 0, 0, 0, brightness, 0, 1, 0, 0, brightness, 0, 0, 1, 0, brightness, 0, 0, 0, 1, 0 });
imageview.setColorFilter(new ColorMatrixColorFilter(matrix));
} /**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
private int dip2px(Context context, float dpValue) {
final float scale = context.getApplicationContext().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
} }

自定义一个仿IOS的弹出框

 package com.example.nanchen.cropimagetest;

 import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView; import java.util.List; /**
* dialog
*
*/
public class SelectDialog extends Dialog implements OnClickListener,OnItemClickListener {
private SelectDialogListener mListener;
private Activity mActivity;
private Button mMBtn_Cancel;
private TextView mTv_Title;
private List<String> mName;
private String mTitle;
private boolean mUseCustomColor = false;
private int mFirstItemColor;
private int mOtherItemColor; public interface SelectDialogListener {
public void onItemClick(AdapterView<?> parent, View view, int position, long id);
} private SelectDialogCancelListener mCancelListener; public interface SelectDialogCancelListener {
public void onCancelClick(View v);
} public SelectDialog(Activity activity, int theme,
SelectDialogListener listener,List<String> names) {
super(activity, theme);
mActivity = activity;
mListener = listener;
this.mName=names; // 设置是否点击外围解散
setCanceledOnTouchOutside(true);
} /**
* @param activity 调用弹出菜单的activity
* @param theme 主题
* @param listener 菜单项单击事件
* @param cancelListener 取消事件
* @param names 菜单项名称
*
*/
public SelectDialog(Activity activity, int theme,SelectDialogListener listener,SelectDialogCancelListener cancelListener ,List<String> names) {
super(activity, theme);
mActivity = activity;
mListener = listener;
mCancelListener = cancelListener;
this.mName=names; // 设置是否点击外围不解散
setCanceledOnTouchOutside(false);
} /**
* @param activity 调用弹出菜单的activity
* @param theme 主题
* @param listener 菜单项单击事件
* @param names 菜单项名称
* @param title 菜单标题文字
*
*/
public SelectDialog(Activity activity, int theme,SelectDialogListener listener,List<String> names,String title) {
super(activity, theme);
mActivity = activity;
mListener = listener;
this.mName=names;
mTitle = title; // 设置是否点击外围可解散
setCanceledOnTouchOutside(true);
} public SelectDialog(Activity activity, int theme,SelectDialogListener listener,SelectDialogCancelListener cancelListener,List<String> names,String title) {
super(activity, theme);
mActivity = activity;
mListener = listener;
mCancelListener = cancelListener;
this.mName=names;
mTitle = title; // 设置是否点击外围可解散
setCanceledOnTouchOutside(true);
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = getLayoutInflater().inflate(R.layout.view_dialog_select,
null);
setContentView(view, new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
Window window = getWindow();
// 设置显示动画
window.setWindowAnimations(R.style.main_menu_animstyle);
WindowManager.LayoutParams wl = window.getAttributes();
wl.x = 0;
wl.y = mActivity.getWindowManager().getDefaultDisplay().getHeight();
// 以下这两句是为了保证按钮可以水平满屏
wl.width = LayoutParams.MATCH_PARENT;
wl.height = LayoutParams.WRAP_CONTENT; // 设置显示位置
onWindowAttributesChanged(wl); //setCanceledOnTouchOutside(false);
initViews();
} private void initViews() {
DialogAdapter dialogAdapter=new DialogAdapter(mName);
ListView dialogList=(ListView) findViewById(R.id.dialog_list);
dialogList.setOnItemClickListener(this);
dialogList.setAdapter(dialogAdapter);
mMBtn_Cancel = (Button) findViewById(R.id.mBtn_Cancel);
mTv_Title = (TextView) findViewById(R.id.mTv_Title); //mMBtn_Cancel.setOnClickListener(this); mMBtn_Cancel.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(mCancelListener != null){
mCancelListener.onCancelClick(v);
}
dismiss();
}
}); if(!TextUtils.isEmpty(mTitle) && mTv_Title != null){
mTv_Title.setVisibility(View.VISIBLE);
mTv_Title.setText(mTitle);
}else{
mTv_Title.setVisibility(View.GONE);
}
} @Override
public void onClick(View v) {
dismiss(); } @Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) { mListener.onItemClick(parent, view, position, id);
dismiss();
}
private class DialogAdapter extends BaseAdapter {
private List<String> mStrings;
private Viewholder viewholder;
private LayoutInflater layoutInflater;
public DialogAdapter(List<String> strings) {
this.mStrings = strings;
this.layoutInflater=mActivity.getLayoutInflater();
} @Override
public int getCount() {
// TODO Auto-generated method stub
return mStrings.size();
} @Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mStrings.get(position);
} @Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
viewholder=new Viewholder();
convertView=layoutInflater.inflate(R.layout.view_dialog_item, null);
viewholder.dialogItemButton=(TextView) convertView.findViewById(R.id.dialog_item_bt);
convertView.setTag(viewholder);
}else{
viewholder=(Viewholder) convertView.getTag();
}
viewholder.dialogItemButton.setText(mStrings.get(position));
if (!mUseCustomColor) {
mFirstItemColor = mActivity.getResources().getColor(R.color.dialog_blue);
mOtherItemColor = mActivity.getResources().getColor(R.color.dialog_blue);
}
if (1 == mStrings.size()) {
viewholder.dialogItemButton.setTextColor(mFirstItemColor);
viewholder.dialogItemButton.setBackgroundResource(R.drawable.dialog_item_bg_only);
} else if (position == 0) {
viewholder.dialogItemButton.setTextColor(mFirstItemColor);
viewholder.dialogItemButton.setBackgroundResource(R.drawable.dialog_item_bg_top);
} else if (position == mStrings.size() - 1) {
viewholder.dialogItemButton.setTextColor(mOtherItemColor);
viewholder.dialogItemButton.setBackgroundResource(R.drawable.dialog_item_bg_buttom);
} else {
viewholder.dialogItemButton.setTextColor(mOtherItemColor);
viewholder.dialogItemButton.setBackgroundResource(R.drawable.dialog_item_bg_center);
}
return convertView;
} } public static class Viewholder {
public TextView dialogItemButton;
} /**
* 设置列表项的文本颜色
*/
public void setItemColor(int firstItemColor, int otherItemColor) {
mFirstItemColor = firstItemColor;
mOtherItemColor = otherItemColor;
mUseCustomColor = true;
} }

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

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

再看看Activity的代码和布局

 package com.example.nanchen.cropimagetest;

 import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Images.Media;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AlertDialog.Builder;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView; import com.example.nanchen.cropimagetest.SelectDialog.SelectDialogListener; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List; public class MainActivity extends AppCompatActivity { private RoundImageView mHeadImage; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mHeadImage = (RoundImageView) findViewById(R.id.main_roundImage);
} private final int PHOTO_PICKED_FROM_CAMERA = 1; // 用来标识头像来自系统拍照
private final int PHOTO_PICKED_FROM_FILE = 2; // 用来标识从相册获取头像
private final int CROP_FROM_CAMERA = 3; private void getIconFromPhoto(){
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(intent, PHOTO_PICKED_FROM_FILE);
} private void selectPhoto() {
List<String> list = new ArrayList<>();
list.add("拍照");
list.add("相册");
showDialog(new SelectDialogListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
switch (position){
case 0:
getIconFromCamera();
break;
case 1:
getIconFromPhoto(); // 从系统相册获取
break;
default:
break;
}
}
},list); } private Uri imgUri; // 由于android手机的图片基本都会很大,所以建议用Uri,而不用Bitmap /**
* 调用系统相机拍照
*/
private void getIconFromCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
imgUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
"avatar_"+String.valueOf(System.currentTimeMillis())+".png"));
intent.putExtra(MediaStore.EXTRA_OUTPUT,imgUri);
startActivityForResult(intent,PHOTO_PICKED_FROM_CAMERA);
} private SelectDialog showDialog(SelectDialogListener listener, List<String> list){
SelectDialog dialog = new SelectDialog(this,
R.style.transparentFrameWindowStyle,listener,list);
dialog.show();
return dialog;
} /**
* 尝试裁剪图片
*/
private void doCrop(){
final ArrayList<CropOption> cropOptions = new ArrayList<>();
final Intent intent = new Intent("com.android.camera.action.CROP");
intent.setType("image/*");
List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent,0);
int size = list.size();
if (size == 0){
UIUtil.showToast(this,"当前不支持裁剪图片!");
return;
}
intent.setData(imgUri);
intent.putExtra("outputX",300);
intent.putExtra("outputY",300);
intent.putExtra("aspectX",1);
intent.putExtra("aspectY",1);
intent.putExtra("scale",true);
intent.putExtra("return-data",true); // only one
if (size == 1){
Intent intent1 = new Intent(intent);
ResolveInfo res = list.get(0);
intent1.setComponent(new ComponentName(res.activityInfo.packageName,res.activityInfo.name));
startActivityForResult(intent1,CROP_FROM_CAMERA);
}else {
// 很多可支持裁剪的app
for (ResolveInfo res : list) {
CropOption co = new CropOption();
co.title = getPackageManager().getApplicationLabel(res.activityInfo.applicationInfo);
co.icon = getPackageManager().getApplicationIcon(res.activityInfo.applicationInfo);
co.appIntent = new Intent(intent);
co.appIntent.setComponent(new ComponentName(res.activityInfo.packageName,res.activityInfo.name));
cropOptions.add(co);
} CommonAdapter<CropOption> adapter = new CommonAdapter<CropOption>(this,cropOptions,R.layout.layout_crop_selector) {
@Override
public void convert(ViewHolder holder, CropOption item) {
holder.setImageDrawable(R.id.iv_icon,item.icon);
holder.setText(R.id.tv_name,item.title);
}
}; AlertDialog.Builder builder = new Builder(this);
builder.setTitle("choose a app");
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startActivityForResult(cropOptions.get(which).appIntent,CROP_FROM_CAMERA);
}
});
builder.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
if (imgUri != null){
getContentResolver().delete(imgUri,null,null);
imgUri = null;
}
}
});
AlertDialog dialog = builder.create();
dialog.show(); }
} @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK){
return;
}
switch (requestCode) {
case PHOTO_PICKED_FROM_CAMERA:
doCrop();
break;
case PHOTO_PICKED_FROM_FILE:
imgUri = data.getData();
doCrop();
break;
case CROP_FROM_CAMERA:
if (data != null){
setCropImg(data);
}
break;
default:
break;
}
} private void setCropImg(Intent picData){
Bundle bundle = picData.getExtras();
if (bundle != null){
Bitmap mBitmap = bundle.getParcelable("data");
mHeadImage.setImageBitmap(mBitmap);
saveBitmap(Environment.getExternalStorageDirectory() + "/crop_"
+System.currentTimeMillis() + ".png",mBitmap);
}
} private void saveBitmap(String fileName,Bitmap bitmap){
File file = new File(fileName);
FileOutputStream fout = null;
try {
file.createNewFile();
fout = new FileOutputStream(file);
bitmap.compress(CompressFormat.PNG,100,fout);
fout.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fout!=null){
fout.close();
}
UIUtil.showToast(MainActivity.this,"保存成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
} public void btnClick(View view) {
selectPhoto();
}
}

布局:

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.nanchen.cropimagetest.MainActivity"> <com.example.nanchen.cropimagetest.RoundImageView
android:id="@+id/main_roundImage"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignParentTop="true"
android:layout_centerInParent="true"
android:src="@drawable/default_avatar"/> <Button
android:id="@+id/main_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/main_roundImage"
android:onClick="btnClick"
android:text="设置头像"/>
</RelativeLayout>

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

github链接:https://github.com/nanchen2251/CropImageDemo

【绝对干货】仿微信QQ设置图形头像裁剪,让你的App从此炫起来~的更多相关文章

  1. Vue3.0网页版聊天|Vue3.x+ElementPlus仿微信/QQ界面|vue3聊天实例

    一.项目简介 基于vue3.x+vuex+vue-router+element-plus+v3layer+v3scroll等技术构建的仿微信web桌面端聊天实战项目Vue3-Webchat.基本上实现 ...

  2. android高仿微信UI点击头像显示大图片效果

    用过微信的朋友朋友都见过微信中点击对方头像显示会加载大图,先贴两张图片说明下: 这种UI效果对用户的体验不错,今天突然有了灵感,试着去实现,结果就出来了.. 下面说说我的思路: 1.点击图片时跳转到另 ...

  3. android仿微信红包动画、Kotlin综合应用、Xposed模块、炫酷下拉视觉、UC浏览器滑动动画等源码

    Android精选源码 仿微信打开红包旋转动画 使用Kotlin编写的Android应用,内容你想象不到 Android手机上的免Root Android系统日志Viewer 一个能让微信 Mater ...

  4. Android仿微信QQ等实现锁屏消息提醒

    demo代码如下: import android.content.Intent; import android.os.Bundle; import android.support.v7.app.App ...

  5. android高仿微信UI点击头像显示大图片效果, Android 使用ContentProvider扫描手机中的图片,仿微信显示本地图片效果

    http://www.cnblogs.com/Jaylong/archive/2012/09/27/androidUI.html http://blog.csdn.net/xiaanming/arti ...

  6. Android项目实战(二十三):仿QQ设置App全局字体大小

    一.项目需求: 因为产品对象用于中老年人,所以产品设计添加了APP全局字体调整大小功能. 这里仿做QQ设置字体大小的功能. QQ实现的效果是,滚动下面的seekbar,当只有seekbar到达某一个刻 ...

  7. Tauri-Vue3桌面端聊天室|tauri+vite3仿微信|tauri聊天程序EXE

    基于tauri+vue3.js+vite3跨桌面端仿微信聊天实例TauriVue3Chat. tauri-chat 运用最新tauri+vue3+vite3+element-plus+v3layer等 ...

  8. iOS天气动画、高仿QQ菜单、放京东APP、高仿微信、推送消息等源码

    iOS精选源码 TYCyclePagerView iOS上的一个无限循环轮播图组件 iOS高仿微信完整项目源码 想要更简单的推送消息,看本文就对了 ScrollView嵌套ScrolloView解决方 ...

  9. 一行实现QQ群组头像,微信群组,圆角等效果. 并支持url直接加载图片

    说点题外话. Coding中我们总是经历着这么几个过程. 学会使用: 不管是API也好, 开源库也好. 总是在最开始的学会去用. 了解实现原理: 可能会因为一些不兼容, 代码的异常状态的处理不够完美等 ...

随机推荐

  1. 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)

    0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...

  2. 一起学微软Power BI系列-使用技巧(5)自定义PowerBI时间日期表

    1.日期函数表作用 经常使用Excel或者PowerBI,Power Pivot做报表,时间日期是一个重要的纬度,加上做一些钻取,时间日期函数表不可避免.所以今天就给大家分享一个自定义的做日期表的方法 ...

  3. 富文本编辑器Simditor的简易使用

    最近打算自己做一个博客系统,并不打算使用帝国cms或者wordpress之类的做后台管理!自己处于学习阶段也就想把从前台到后台一起谢了.好了,废话不多说了,先来看看富文本编辑器SimDitor,这里是 ...

  4. "NHibernate.Exceptions.GenericADOException: could not load an entity" 解决方案

     今天,测试一个项目的时候,抛出了这个莫名其妙的异常,然后就开始了一天的调试之旅... 花了很长时间,没有从代码找出任何问题... 那么到底哪里出问题呢? 根据下面那段长长的错误日志: -- ::, ...

  5. 著名ERP厂商的SSO单点登录解决方案介绍一

          SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次主要的登录映射到其他应用中用于同一个用户 ...

  6. Visual Studio 2013 添加一般应用程序(.ashx)文件到SharePoint项目

    默认,在用vs2013开发SharePoint项目时,vs没有提供一般应用程序(.ashx)的项目模板,本文解决此问题. 以管理员身份启动vs2013,创建一个"SharePoint 201 ...

  7. Oracle 表空间和用户权限管理

    一. 表空间 Oracle数据库包含逻辑结构和物理结构. 数据库的物理结构指的是构成数据库的一组操作系统文件. 数据库的逻辑结构是指描述数据组织方式的一组逻辑概念以及它们之间的关系. 表空间是数据库逻 ...

  8. 08讲browse命令的使用技巧

    .浏览所有parts ,使用技巧 .浏览所有 nets,使用技巧 在上图中选择nets .浏览所有 offpage connector,使用技巧 如上 .浏览所有 DRC makers,使用技巧 5. ...

  9. Android连接网络打印机进行打印

    首先这是网络打印工具类,通过Socket实现,多说一句,网络打印机端口号一般默认的是9100 package com.Ieasy.Tool; import android.annotation.Sup ...

  10. AutoMapper(四)

    返回总目录 自定义值解析 虽然AutoMapper覆盖了相当一部分目标成员的映射场景,但是还有 1-5%的目标值需要解析处理一下.很多时候,自定义的值解析是可以放在领域层的领域逻辑.然而,如果该逻辑只 ...