一、UI显示
今天我来总结一下应用中我们常用的更改头像的功能。先上图看一下效果。
其实我们在更改头像的时候,我们分为两个部分
1、使用手机的拍照功能(可以使用系统的照相机,也可以是自定义的照相机)
2、使用手机中原有的照片进行使用
这里我进行一起总结。
二、代码的分析
1、使用照相机进行拍照上传头像
try {
Intent _intentTakePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (FileManager.hasSdCard()){
_intentTakePhoto.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(getExternalCacheDir(), mPictureName)));
}
startActivityForResult(_intentTakePhoto,Constants.ActivityCode.REQUEST_CODE_CAMERA);
}catch (Exception _e){
ExceptionHandler.onException(_e);
}
/**
* judge has card
* @return
*/
public static boolean hasSdCard(){
try {
String _state = Environment.getExternalStorageState();
if (_state.equals(Environment.MEDIA_MOUNTED))
return true;
}catch (Exception _e){
ExceptionHandler.onException(_e);
return false;
}
return false;
}
讲解:
1、我们先使用MediaStore.ACTION_IMAGE_CAPTURE的Intent来调出相机界面
2、我们拍完照片需要把照片保存到手机的存储卡中,这里我们使用hasSdCard()方法来进行判断是否又SD卡
3、当有SD卡的时候,我们将拍完的照片存储到SD卡中
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_CANCELED){
Toast.makeText(ActivityMyInfo.this, R.string.view_random_code_dialog_cancel, Toast.LENGTH_SHORT).show();
return;
}
switch (requestCode){
case Constants.ActivityCode.REQUEST_CODE_CAMERA:
if (FileManager.hasSdCard()){
if(null == mPictureName)
return;
File _cameraFile = new File(getExternalCacheDir(), mPictureName);
cropRawPhoto(Uri.fromFile(_cameraFile));
}else {
Toast.makeText(ActivityMyInfo.this, R.string.activity_my_info_toast_no_sdcard, Toast.LENGTH_SHORT).show();
}
break;
case Constants.ActivityCode.REQUEST_CODE_CROP_PICTURE:
Bundle _headBundle = data.getExtras();
Bitmap _headBitmap = null,_bitmapRound = null,_bitmapComp = null;
if (null != _headBundle){
_headBitmap = _headBundle.getParcelable("data");
}else {
Uri _fileUri = data.getData();
if (null != _fileUri){
try {
_headBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),_fileUri);
} catch (IOException e) {
e.printStackTrace();
}
}else{
Toast.makeText(ActivityMyInfo.this, R.string.activity_my_info_toast_dont_get_head, Toast.LENGTH_SHORT).show();
return;
}
}
_bitmapComp = ImageUtil.compBitmap(_headBitmap);
mPicturePath = String.valueOf(FileManager.saveBitmapToSD(this,_bitmapComp,mPictureName));
isNeedUploadHeadImage = true;
mImageViewHeadIcon.setImageBitmap(_bitmapComp);
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
/**
* crop picture
* @param uri
*/
public void cropRawPhoto(Uri uri) {
try {
Intent _intent = new Intent("com.android.camera.action.CROP");
_intent.setDataAndType(uri, "image/*");
_intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(getExternalCacheDir(), mPictureName)));
// 设置裁剪
_intent.putExtra("crop", "true");
// aspectX , aspectY :宽高的比例
_intent.putExtra("aspectX", 1);
_intent.putExtra("aspectY", 1);
// outputX , outputY : 裁剪图片宽高
_intent.putExtra("outputX", 250);
_intent.putExtra("outputY", 250);
_intent.putExtra("return-data", true);
startActivityForResult(_intent, Constants.ActivityCode.REQUEST_CODE_CROP_PICTURE);
}catch (Exception _e){
ExceptionHandler.onException(_e);
}
}
讲解:
1、使用了startActivityForResult()之后,我们在onActivityResult()的函数中接收拍照后的结果
2、在取消拍照后,我使用了一个Toast来提示取消了拍照
3、如果拍照后返回成功,这里使用了cropRawPhoto()来进行对拍完的照片进行剪切
4、剪切成功之后,我们在最后一个case中进行处理剪切后的数据
5、这里要注意一点:剪切之后这里的Bundle中数据可能为空,原因因为自己暂时还没有研究,欢迎在坐的大神留言告诉我一下。我们这里就分开进行处理
6、获取到了这里的图片数据Bitmap,还需要对获取到的Bitmap进行处理,原因是图片太大会出现OOM的问题。我在文末就直接上压缩图片的代码了,大家可以研究一下。
7、最后使用fresco进行图片的显示
8、如果上传到服务器的话,最后我们还可以在上传服务器成功之后,删除图片文件,不然图片文件就一直在内存卡中了
2、使用选择图片进行上传
try {
Intent _intentSelectPhoto = new Intent(Intent.ACTION_PICK);
_intentSelectPhoto.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");
startActivityForResult(_intentSelectPhoto,Constants.ActivityCode.REQUEST_CODE_GALLERY);
}catch (Exception _e){
ExceptionHandler.onException(_e);
}
讲解:
1、使用Intent.ACTION_PICK的Intent来打开相册,进行选择照片
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_CANCELED){
Toast.makeText(ActivityMyInfo.this, R.string.view_random_code_dialog_cancel, Toast.LENGTH_SHORT).show();
return;
}
switch (requestCode){
case Constants.ActivityCode.REQUEST_CODE_GALLERY:
cropRawPhoto(data.getData());
break;
case Constants.ActivityCode.REQUEST_CODE_CROP_PICTURE:
Bundle _headBundle = data.getExtras();
Bitmap _headBitmap = null,_bitmapRound = null,_bitmapComp = null;
if (null != _headBundle){
_headBitmap = _headBundle.getParcelable("data");
}else {
Uri _fileUri = data.getData();
if (null != _fileUri){
try {
_headBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),_fileUri);
} catch (IOException e) {
e.printStackTrace();
}
}else{
Toast.makeText(ActivityMyInfo.this, R.string.activity_my_info_toast_dont_get_head, Toast.LENGTH_SHORT).show();
return;
}
}
_bitmapComp = ImageUtil.compBitmap(_headBitmap);
mPicturePath = String.valueOf(FileManager.saveBitmapToSD(this,_bitmapComp,mPictureName));
isNeedUploadHeadImage = true;
mImageViewHeadIcon.setImageBitmap(_bitmapComp);
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
讲解:
1、这里比拍照选择会比较简单一点,不过也可以使用剪切图片来进行上传
2、其余的都和拍照后剪切是一样的
三、代码展示
最后全部代码贴出来,因为没有注释,如果大家有什么问题,欢迎找我。
1、take picture
/**
* take picture
*/
public void takePicture(){
try {
Intent _intentTakePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (FileManager.hasSdCard()){
_intentTakePhoto.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(getExternalCacheDir(), mPictureName)));
}
startActivityForResult(_intentTakePhoto,Constants.ActivityCode.REQUEST_CODE_CAMERA);
}catch (Exception _e){
ExceptionHandler.onException(_e);
}
}
2、pick picture
/**
* pick picture
*/
public void pickPicture(){
try {
Intent _intentSelectPhoto = new Intent(Intent.ACTION_PICK);
_intentSelectPhoto.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");
startActivityForResult(_intentSelectPhoto,Constants.ActivityCode.REQUEST_CODE_GALLERY);
}catch (Exception _e){
ExceptionHandler.onException(_e);
}
}
3、onActivityResult()函数中的处理
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_CANCELED){
Toast.makeText(ActivityMyInfo.this, R.string.view_random_code_dialog_cancel, Toast.LENGTH_SHORT).show();
return;
}
switch (requestCode){
case Constants.ActivityCode.REQUEST_CODE_CAMERA:
if (FileManager.hasSdCard()){
if(null == mPictureName)
return;
File _cameraFile = new File(getExternalCacheDir(), mPictureName);
cropRawPhoto(Uri.fromFile(_cameraFile));
}else {
Toast.makeText(ActivityMyInfo.this, R.string.activity_my_info_toast_no_sdcard, Toast.LENGTH_SHORT).show();
}
break;
case Constants.ActivityCode.REQUEST_CODE_GALLERY:
cropRawPhoto(data.getData());
break;
case Constants.ActivityCode.REQUEST_CODE_CROP_PICTURE:
Bundle _headBundle = data.getExtras();
Bitmap _headBitmap = null,_bitmapRound = null,_bitmapComp = null;
if (null != _headBundle){
_headBitmap = _headBundle.getParcelable("data");
}else {
Uri _fileUri = data.getData();
if (null != _fileUri){
try {
_headBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),_fileUri);
} catch (IOException e) {
e.printStackTrace();
}
}else{
Toast.makeText(ActivityMyInfo.this, R.string.activity_my_info_toast_dont_get_head, Toast.LENGTH_SHORT).show();
return;
}
}
_bitmapComp = ImageUtil.compBitmap(_headBitmap);
mPicturePath = String.valueOf(FileManager.saveBitmapToSD(this,_bitmapComp,mPictureName));
isNeedUploadHeadImage = true;
mImageViewHeadIcon.setImageBitmap(_bitmapComp);
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
4、剪切图片
/**
* crop picture
* @param uri
*/
public void cropRawPhoto(Uri uri) {
try {
Intent _intent = new Intent("com.android.camera.action.CROP");
_intent.setDataAndType(uri, "image/*");
_intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(getExternalCacheDir(), mPictureName)));
// 设置裁剪
_intent.putExtra("crop", "true");
// aspectX , aspectY :宽高的比例
_intent.putExtra("aspectX", 1);
_intent.putExtra("aspectY", 1);
// outputX , outputY : 裁剪图片宽高
_intent.putExtra("outputX", 250);
_intent.putExtra("outputY", 250);
_intent.putExtra("return-data", true);
startActivityForResult(_intent, Constants.ActivityCode.REQUEST_CODE_CROP_PICTURE);
}catch (Exception _e){
ExceptionHandler.onException(_e);
}
}
5、对图片进行处理,压缩图片,圆图像等
/**
*compression imageview
* @param _imageBitmap
* @return
*/
public static Bitmap compBitmap(Bitmap _imageBitmap) {
try {
if (null == _imageBitmap)
return null;
ByteArrayOutputStream _baos = new ByteArrayOutputStream();
_imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, _baos);
if( _baos.toByteArray().length / 1024>1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
_baos.reset();//重置baos即清空baos
_imageBitmap.compress(Bitmap.CompressFormat.JPEG, 50, _baos);//这里压缩50%,把压缩后的数据存放到baos中
}
ByteArrayInputStream isBm = new ByteArrayInputStream(_baos.toByteArray());
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
newOpts.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
int w = newOpts.outWidth;
int h = newOpts.outHeight;
//现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
float hh = 800f;//这里设置高度为800f
float ww = 480f;//这里设置宽度为480f
//缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
int be = 1;//be=1表示不缩放
if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;//设置缩放比例
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
newOpts.inJustDecodeBounds = false;
isBm = new ByteArrayInputStream(_baos.toByteArray());
bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
return compressImage(bitmap);//压缩好比例大小后再进行质量压缩
}catch (Exception _e){
ExceptionHandler.onException(_e);
return null;
}
public static Bitmap compressImage(Bitmap _image) {
try {
if (null == _image)
return null;
ByteArrayOutputStream _baos = new ByteArrayOutputStream();
_image.compress(Bitmap.CompressFormat.JPEG, 100, _baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
int options = 100;
while ( _baos.toByteArray().length / 1024>100) {//循环判断如果压缩后图片是否大于100kb,大于继续压缩
_baos.reset();//重置baos即清空baos
_image.compress(Bitmap.CompressFormat.JPEG, options, _baos);//这里压缩options%,把压缩后的数据存放到baos中
options -= 10;//每次都减少10
}
ByteArrayInputStream isBm = new ByteArrayInputStream(_baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
return makeRoundCorner(bitmap);
}catch (Exception _e){
ExceptionHandler.onException(_e);
return null;
}
}
/**
* 转换图片成圆形
* @param bitmap 传入Bitmap对象
* @return
*/
public static Bitmap makeRoundCorner(Bitmap bitmap)
{
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int left = 0, top = 0, right = width, bottom = height;
float roundPx = height/2;
if (width > height) {
left = (width - height)/2;
top = 0;
right = left + height;
bottom = height;
} else if (height > width) {
left = 0;
top = (height - width)/2;
right = width;
bottom = top + width;
roundPx = width/2;
}
Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
int color = 0xff424242;
Paint paint = new Paint();
Rect rect = new Rect(left, top, right, bottom);
RectF rectF = new RectF(rect);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}