实现:
1、在 xml 布局中实现一个图片布局
2、通过 button 控件弹框,让用户选择拍照还是从相册选择
3、得到位图,将位图按自己的需求处理(裁切成方形圆形)
4、在图片布局上显示位图 (有需要的还有可以保存位图、上传服务器)
效果:
界面显示
点击更改图像
在这里选择时拍照获取位图还是从相册选择
实现详情:
1、在 xml 布局中实现一个图片布局
简单的在需要的地方布局就好了,我 demo 的布局为:
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center"> <ImageView android:id="@+id/images" android:layout_width="90dp" android:layout_height="90dp" android:src="@mipmap/head"/> </LinearLayout> <Button android:id="@+id/change" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="更改图像"/>
2、通过 button 控件对话框,让用户选择拍照还是从相册选择
对话框的话,可以根据自己需要,自定义或者调用系统弹框都行
自定义弹框可以参照我的另一篇:android自定义对话框
http://blog.csdn.net/weixin_41454168/article/details/79538149
这里的话,我就用的系统对话框
change = (Button) findViewById(R.id.change); change.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //点击更改图像按钮后,就弹一个对话框,问:是拍照还是在相册中选? AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this) .setTitle("更改头像") .setMessage("请获取新的头像!") .setNegativeButton("拍照", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { //调用摄像头拍照 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); uri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "temp_image.jpg")); // 将拍照所得的相片保存到SD卡根目录 intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(intent, TAKE_PICTURE); } }) .setPositiveButton("相册", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { //调用相册、图库 Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("image/*");//选择图片 startActivityForResult(intent, CHOOSE_PICTURE); } }).create(); alertDialog.show(); } });
从源码中可以看到,无论是选择拍照还是相册,都会用 Intent 与系统通信,
从而调用系统相机或是系统图库
3、得到位图,将位图按自己的需求处理(裁切成方形圆形)
经过第二步后,拍照或是相册这些活动都会对系统都会有一个返回,
我们可以通过 onActivityResult(int requestCode, int resultCode, Intent data) 做出判断并处理:
//这里返回活动结果 (拍照或选择的图片) @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { switch (requestCode) { case TAKE_PICTURE: cutImage(uri); // 对图片进行裁剪处理 break; case CHOOSE_PICTURE: cutImage(data.getData()); // 对图片进行裁剪处理 break; case CROP_SMALL_PICTURE: if (data != null) { setImageToView(data); // 让刚才选择裁剪得到的图片显示在界面上 } break; } } }
通过上面这个方法,判断出了用户进行了什么操作,
这时,如果这些操作有返回位图,就对这个位图进行处理(这里主要是裁剪位图:方形、圆形)
// 裁剪图片 protected void cutImage(Uri uri) { //调用系统自带的图片裁切功能(这里裁成正方形) Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*"); // 设置裁剪 intent.putExtra("crop", "true"); // aspectX aspectY 是宽高的比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // outputX outputY 是裁剪图片宽高 intent.putExtra("outputX", 150); intent.putExtra("outputY", 150); intent.putExtra("return-data", true); startActivityForResult(intent, CROP_SMALL_PICTURE); }
这时,位图已经是正方形了,如果有需要还可以裁切成圆形的(头像之类)
就需要定义一个方法来裁切,我把它写成了一个工具类:
import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.net.Uri; /** * Created by Administrator on 2018/3/15 0015. * 将位图切割成圆形 */ public class CircleUtils { //这个方法将位图切割成圆形 public static Bitmap toRoundBitmap(Bitmap bitmap) { 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; left = 0; top = 0; right = width; bottom = 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; } Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(output); final int color = 0xff424242; 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.drawCircle(roundPx, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(bitmap, src, dst, paint); return output; } }如需要用到,直接调用就行了
4、在图片布局上显示位图 (有需要的还有可以保存位图、上传服务器)
将位图改成自己想要的样式之后,就可以显示在界面上去:
// 显示裁剪之后的图片数据 protected void setImageToView(Intent data) { Bundle extras = data.getExtras(); if (extras != null) { try { bitmap = extras.getParcelable("data"); //如果需要保存或上传没有切割成圆的位图,在这个位置应该可以(没试过) // 将位图处理成圆形(如果不加这行代码则显示正方形的图片) bitmap = CircleUtils.toRoundBitmap(bitmap); images.setImageBitmap(bitmap); //也可以在这里与服务器交互或保存位图 } catch (Exception e) { Log.e(TAG, e.getMessage()); } } }
这里就是将 bitmap 通过 setImageBitmap() 方法放入布局中去如下
images.setImageBitmap(bitmap);
至于上传服务器或保存位图,就自己研究一下吧!
源码:https://github.com/iscopy/HeadPortrait