最近公司项目,其中有一个用户头像上传的模块,包括调用手机相机拍照上传,以及调用手机图库上传两种方式。在网上收集整理了许多资料,最后才达到了自己的预期,先看效果图。
首先点击详细界面里面头像栏,然后弹出一个activity,这里设置了一下android:theme=”@android:style/Theme.Dialog” : Activity显示为对话框模式,加上一个动画效果,就达到了图示的效果。之所以没用popwindow,因为业务稍微复杂,以后还要上传图片到服务器,用activity实现效果一样,方便管理,相对独立。点击拍照上传,跳转到拍照界面,拍照完成以后,跳转到截取照片的界面,如图所示,点击应用,选择的头像会显示在之前的界面上面;
点击图库上传,会跳转到手机图库,这个手机不一样,界面也会有所差别。然后选择一张自己喜欢的图片,
直接跳转到截取界面,如图所示,点击应用,选择的头像会显示在之前的界面上。
最后就是把截取以后的图片全部保存在了自己定义的文件夹之下,都是320*320px大小的图片,以后再把图片上传到服务器即可。
下面就是具体的实现:
1.页面布局:
<RelativeLayout
android:id="@+id/doctor_headpicture_rl"
android:layout_width="match_parent"
android:layout_height="@dimen/patient_item_hei"
android:background="@color/white" >
<com.jxj.followuphelper.view.RoundImageView
android:id="@+id/doctor_head_img"
style="@style/w_wrap_h_wrap"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginBottom="@dimen/margin_bottom"
android:layout_marginRight="@dimen/activity_bar"
android:layout_marginTop="@dimen/margin_bottom"
android:src="@drawable/head_picture_man"
imagecontrol:border_outside_color="@color/gray"
imagecontrol:border_thickness="@dimen/line_width" />
<TextView
style="@style/w_wrap_h_wrap"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/margin"
android:text="@string/set_doctor_picture"
android:textColor="@color/black"
android:textSize="@dimen/title_name_text" />
<ImageView
style="@style/w_wrap_h_wrap"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="18dp"
android:adjustViewBounds="true"
android:background="@drawable/right_arrow" />
</RelativeLayout>
布局比较简单,多余代码就不贴了,重点是那个圆形头像的实现,用的是一个继承自imageview的自定义view,外面的边框可以自己设置,使用起来十分方便。
2.功能实现:
private void initviews() {
headPictureCameraRl.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// 指定照相机拍照后图片的存储路径,这里存储在自己定义的文件夹下
if (Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState())) {
// 创建一个文件夹对象,赋值为外部存储器的目录
File sdcardDir = Environment.getExternalStorageDirectory();
// 得到一个路径,内容是sdcard的文件夹路径和名字
String path = sdcardDir.getPath()
+ "/FollowUpHelper/cardImages";
File photofile = new File(path);
if (!photofile.exists()) {
// 若不存在,创建目录,可以在应用启动的时候创建
photofile.mkdirs();
} else {
imageUri = Uri.fromFile(new File(photofile,
getHeadPictureName()));
// 拍照我们用Action为MediaStore.ACTION_IMAGE_CAPTURE,
// 有些人使用其他的Action但我发现在有些机子中会出问题,所以优先选择这个
Intent intent = new Intent(
MediaStore.ACTION_IMAGE_CAPTURE);
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
// 保存照片在自定义的文件夹下面
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, 1);
}
} else {
UiUtil.showToast(context, "SD卡不可用");
return;
}
}
});
headPicturePhotoRl.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
try {
// 选择照片的时候也一样,我们用Action为Intent.ACTION_GET_CONTENT,
// 有些人使用其他的Action但我发现在有些机子中会出问题,所以优先选择这个
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, 2);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
});
首先判断手机的SD卡是否可用,然后获取SD卡的绝对路径,在下面创建自己定义的文件夹用来存储截取的图片。接下里就是给每张截取的图片创建一个uri,用于区分每张图片,后面方法用的是getHeadPictureName(),根据时间的不同来区分。
public String getHeadPictureName() {
Date date = new Date(System.currentTimeMillis());
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
return dateFormat.format(date) + ".jpg";
}
接下来就是调用手机相机与手机图库来选择头像了,注意在选择相机上传的时候加上这句话,intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);这样拍照的照片会暂时保存在自己定义的文件夹下面。手机拍照与图库选择都是使用startActivityForResult()来处理返回的结果。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Intent intent = new Intent("com.android.camera.action.CROP");
Uri uri = null;
//如果返回的是拍照上传
if (data == null) {
uri = imageUri;
} //返回的是图库上传
else {
uri = data.getData();
}
if (resultCode == RESULT_OK) {
switch (requestCode) {
case 1:
intent.setDataAndType(uri, "image/*");
//下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪
intent.putExtra("crop", true);
// 设置裁剪尺寸
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 320);
intent.putExtra("outputY", 320);
intent.putExtra("return-data", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, 3);
break;
case 2:
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", true);
// 设置裁剪尺寸
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 320);
intent.putExtra("outputY", 320);
intent.putExtra("return-data", true);
// 创建一个文件夹对象,赋值为外部存储器的目录
File sdcardDir = Environment.getExternalStorageDirectory();
// 得到一个路径,内容是sdcard的文件夹路径和名字
String path = sdcardDir.getPath()
+ "/FollowUpHelper/cardImages";
File photofile = new File(path);
uri = Uri.fromFile(new File(photofile, getHeadPictureName()));
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, 3);
break;
case 3:
if (data != null) {
Intent resultIntent = getIntent();
Bundle bundle = data.getExtras();
Bitmap myBitmap = bundle.getParcelable("data");
resultIntent.putExtra("myBitmap", myBitmap);
setResult(1, resultIntent);
finish();
}
break;
default:
break;
}
}
通过onActivityResult来处理返回的结果,intent代表跳转到裁剪的界面,然后进行判断,如果是拍照上传的话,图片已经存在自己定义的文件下下面,所以取回的data为空,将imageuri的值传给uri;如果是图库选择上传的话,可以直接从data里面拿到图片的uri;依次设置裁剪类型,可裁剪,裁剪宽高比例与尺寸。然后就是保存裁剪完的图像,在调用手机拍照时,已经创建好了文件夹与文件名,直接覆盖即可;在调用图库上传时候,需要自己重新创建文件夹将裁剪以后的照片保存进来,不加这个的话,会提示“无法保存裁剪完的图片”。保存好裁剪图片以后,接下来就是进行图片的处理了。
这个界面是上一个界面跳转过来的,所以我这里要将图片的bitmap作为返回结果传递给上一个界面,进行显示。
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
if (resultCode == 1) {
switch (requestCode) {
case 1:
Bundle data = intent.getExtras();
doctorHeadImg.setImageBitmap((Bitmap) data.get("myBitmap"));
break;
default:
break;
}
}
}
很简单的处理一下,然后将照片显示在自定义的view里面即可。最后可以在自己定义的文件夹下面找到裁剪以后的图片,以后用来进行头像的上传。
欧了~~~