本帖最后由 大山哥哥 于 2017-6-27 20:24 编辑
在开发的时候我们经常遇到一种需求,就是让用户上传一张图片作为头像。这个图片可能是从相册中选择的,也可能是使用摄像头现拍的。不过得到的图片都会进行一步裁剪的操作。下面我们就来实现一下这个需求。
首先我们定义一个Activity,布局里只放置一个按钮和一个ImageView,按钮点击的时候让用户选择并裁剪图片,ImageView作为最终显示结果的View对象。布局代码如下:
[AppleScript] 纯文本查看 复制代码 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_crop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="点"/>
<ImageView
android:id="@+id/iv_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
接下来在Activity中设置button的点击事件,当按钮被点击的时候就弹出一个对话框来让用户选择是从相册还是拍照得到图片。
弹窗代码如下:
[AppleScript] 纯文本查看 复制代码 private void showDialog() {
new AlertDialog.Builder(this)
.setTitle("设置头像")
.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
Intent intentFromGallery = new Intent();
intentFromGallery.setType("image/*"); // 设置文件类型
intentFromGallery.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intentFromGallery,IMAGE_REQUEST_CODE);
break;
case 1:
Intent intentFromCapture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// 判断存储卡是否可以用,可用进行存储
if (hasSdcard()) {
intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(new File(Environment.getExternalStorageDirectory(),IMAGE_FILE_NAME)));
}
startActivityForResult(intentFromCapture,CAMERA_REQUEST_CODE);
break;
}
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();
}
其中,点击第一个选项会打开相册。通过Intent打开系统相册,通过intentFromGallery.setType("image/*")设置文件类型为图片;通过intentFromGallery.setAction(Intent.ACTION_GET_CONTENT)设置要打开系统的相册应用,然后拉起界面打开相册。当用户选择相册中的图片时,会回调到onActivityResult方法。在这个里面我们可以处理返回的图片进行裁剪。 点击第二个选项会调用系统的摄像机应用,通过设置action为MediaStore.ACTION_IMAGE_CAPTURE拉起摄像机。其中通过intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(new File(Environment.getExternalStorageDirectory(),IMAGE_FILE_NAME)))设置拍摄的照片的存储位置。然后拍照成功后回调到onActivityResult方法。同样的,我们对拍摄的图片进行裁剪。
[AppleScript] 纯文本查看 复制代码 @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// 结果码不等于取消时候
if (resultCode != RESULT_CANCELED) {
switch (requestCode) {
case IMAGE_REQUEST_CODE:
startPhotoZoom(data.getData());
break;
case CAMERA_REQUEST_CODE:
if (hasSdcard()) {
File tempFile = new File(Environment.getExternalStorageDirectory(),IMAGE_FILE_NAME);
startPhotoZoom(Uri.fromFile(tempFile));
} else {
Toast.makeText(context, "未找到存储卡,无法存储照片!", Toast.LENGTH_SHORT).show();
}
break;
case RESULT_REQUEST_CODE:
if (data != null) {
setImageToView(data);
}
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
当用户没有选择取消的时候会走到switch的 IMAGE_REQUEST_CODE分支或CAMERA_REQUEST_CODE分支,从而调用startPhotoZoom进行图片的裁剪。我们一起来看看如何实现裁剪的逻辑吧。
[AppleScript] 纯文本查看 复制代码 /**
* 裁剪图片方法实现
*
* @param uri
*/
public void startPhotoZoom(Uri uri) {
if(uri==null){
Log.i("tag", "The uri is not exist.");
}
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", 320);
intent.putExtra("outputY", 320);
intent.putExtra("return-data", true);
startActivityForResult(intent, 2);
}
很简单,还是拉起界面,Intent的action设置为com.android.camera.action.CROP即可,不过需要设置一下参数。首先crop代表是否进行裁剪,我们设置为true,aspectX和aspectY代表的事宽高的比例,我们保持1:1的比例。outputX和outputY是输出裁剪之后的图片宽高,是以像素为单位的,这里我设置了320,具体大小根据自己的项目需求设置。然后return-data代表需要返回图片。拉起Activity,进入裁剪的界面。
途中的橙色方框就是裁剪的范围,可自由拖动,点击保存后还是会把结果返回到我们最初的Activity的onActivityResult方法里。这一次触发switch的RESULT_REQUEST_CODE分支,得到最终的图片结果。可以进行显示了!
[AppleScript] 纯文本查看 复制代码 /**
* 保存裁剪之后的图片数据
*
*/
private void setImageToView(Intent data) {
Bundle extras = data.getExtras();
if (extras != null) {
Bitmap photo = extras.getParcelable("data");
ImageView iv_img = (ImageView) findViewById(R.id.iv_img);
iv_img.setImageBitmap(photo);
}
}
这里很简单,直接把图片拿出来,设置到界面的ImageView上即可。这样,我们就把整个需求实现了,是不是很简单。
|