简介
APP用户更改头像是较为常用的功能,有如下步骤:
- 获取相机的权限和外部存储的读写权限
- 点击修改头像按钮,弹出选择使用相机或者相册菜单;
- 通过相机或者相册选择合适的头像后进入裁剪界面;
- 将裁剪完成后的头像显示以及保存本地;
- 将头像上传服务器。
代码实现
1.获取权限
首先需要获取相机的权限和外部存储的读写权限,获取权限方式可以参考Android高效处理权限——EasyPermissions框架的使用
2.弹窗菜单选择
可以参考Android GUI开发:PopUpWindow窗口的实现方式
3.选择头像图片
拍照
/**
* 从相机获取图片
*/
private void getPicFromCamera() {
//用于保存调用相机拍照后所生成的文件
File mTempFile = new File(this.getExternalCacheDir().getPath(); + "/picture/", System.currentTimeMillis() + ".png");
if (!mTempFile.getParentFile().exists()) {
mTempFile.getParentFile().mkdirs();
}
//跳转到调用系统相机
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//判断版本
//如果在Android7.0以上,使用FileProvider获取Uri
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".FileProvider", mTempFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
} else { //否则使用Uri.fromFile(file)方法获取Uri
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTempFile));
}
startActivityForResult(intent, CAMERA_REQUEST_CODE);
}
有关于FileProvider的知识可以参考Android 7.0之FileProvider——通过FileProvider来获取content uri
相册
/**
* 从相册获取图片
*/
private void getPicFromAlbm() {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, ALBUM_REQUEST_CODE);
}
裁剪
/**
* 裁剪图片方法实现
*
* @param uri
*/
protected void startPhotoZoom(Uri uri) {
if (uri == null) {
Log.i("tag", "The uri is not exist.");
}
// tempUri = uri;
Intent intent = new Intent("com.android.camera.action.CROP");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.setDataAndType(uri, "image/*");
// 设置裁剪
intent.putExtra("crop", "true");
// aspectX aspectY 是宽高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
// outputX outputY 是裁剪图片宽高
intent.putExtra("outputX", 500);
intent.putExtra("outputY", 500);
intent.putExtra("return-data", false);
File out = new File(getPath());
if (!out.getParentFile().exists()) {
out.getParentFile().mkdirs();
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(out));
startActivityForResult(intent, CROP_SMALL_PICTURE);
}
//裁剪后的地址
public String getPath() {
//resize image to thumb
if (mFile == null) {
mFile = SDCardUtil.getCache(this) + "/picture/picture_shear.png";
}
return mFile;
}
常见问题:
在使用系统自带的剪切图片工具时,通常只能设置一些比较小的值,像
intent.putExtra("outputX", 320);
intent.putExtra("outputY", 320);
剪切后图片的尺寸不能设置为过大,经测试到480就会出现卡住的现象,为什么呢?
原因是在于Intent 的data域最大传递的值的大小约为1M,所以图片的BITMAP当超过1M时就会失败。通常我们只是设置头像可以用这个方法,那么如果我们要剪切显示一些比较大的图片呢?怎么做呢?
该方法就是先设置为return-data设为false,不从data域获取图片,而是越过这个桥梁,通过我们刚刚在剪切图片后设置的路径目录和名称来单独获取这个图片,就可以完美显示了。如果不设置return-data为false,那么就会默认通过data返回,从而造成卡住现像。
return-data:是将结果保存在data中返回,在onActivityResult中,直接调用intent.getdata()就可以获取值了,这里设为fase,就是不让它保存在data中
MediaStore.EXTRA_OUTPUT:由于我们不让它保存在Intent的data域中,但我们总要有地方来保存我们的图片,这个参数就是将图片保存到SD卡中,对应Value中保存的URI就是指定的保存地址。
附上裁剪属性表:
附加选项 | 数据类型 | 描述 |
crop | String | 发送裁剪信号 |
aspectX | int | X方向上的比例 |
aspectY | int | Y方向上的比例 |
outputX | int | 裁剪区的宽 |
outputY | int | 裁剪区的高 |
scale | boolean | 是否保留比例 |
return-data | boolean | 是否将数据保留在Bitmap中返回 |
data | Parcelable | 相应的Bitmap数据 |
circleCrop | String | 圆形裁剪区域? |
MediaStore.EXTRA_OUTPUT ("output") | URI | 将URI指向相应的file:///...,详见代码示例 |
outputFormat | String | 输出格式,一般设为Bitmap格式:Bitmap.CompressFormat.JPEG.toString() |
noFaceDetection | boolean | 是否取消人脸识别功能 |
4.返回处理图片
//相册请求码
private static final int ALBUM_REQUEST_CODE = 1;
//相机请求码
private static final int CAMERA_REQUEST_CODE = 2;
//剪裁请求码
private static final int CROP_SMALL_PICTURE = 3;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
switch (requestCode) {
//调用相机后返回
case CAMERA_REQUEST_CODE:
if (resultCode == RESULT_OK) {
//用相机返回的照片去调用剪裁也需要对Uri进行处理
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri contentUri = FileProvider.getUriForFile(this, getPackageName() + ".FileProvider", mTempFile);
//开始对图片进行裁剪处理
startPhotoZoom(contentUri);
} else {
//开始对图片进行裁剪处理
startPhotoZoom(Uri.fromFile(mTempFile));
}
}
break;
//调用相册后返回
case ALBUM_REQUEST_CODE:
if (resultCode == RESULT_OK) {
Uri uri = intent.getData();
// 开始对图片进行裁剪处理
startPhotoZoom(uri);
}
break;
//调用剪裁后返回
case CROP_SMALL_PICTURE:
if (intent != null) {
Bitmap photo = BitmapFactory.decodeFile(mFile);
// 让刚才选择裁剪得到的图片显示在界面上
headerImage.setImageDrawable(new BitmapDrawable(getResources(), photo));
//将头像上传服务器
}
break;
}
}