追风赶月莫停留,平芜尽处是春山。这篇文章主要讲述Android--利用相机或相册截取用户头像(解决了miui无法截取,以及部分机型拍照无返回Uri)相关的知识,希望能为你提供帮助。
声明 本文的Demo可用于从本地获取用户头像时使用,
解决了有些手机系统相机拍照后获取不到拍摄照片的问题,
以及解决小米miui系统调用系统裁剪图片功能camera.action.CROP后崩溃或重新打开app的问题。
- 修改了部分机型拍照后返回的是缩略图的临时文件的问题。
UtilClass.requestPermission(ChangeMyDataActivityCopy.this,
android.Manifest.permission.CAMERA);
chooseUserImageDialog =
new ChooseImageDialog(mContext, new View.OnClickListener() {
@
Override
public void onClick(View v) {
chooseUserImageDialog.dismiss();
switch (v.getId()) {
case R.id.takePhotoBtn: {
String state =
Environment.getExternalStorageState();
if (state.equals(Environment.MEDIA_MOUNTED)) {
Intent getImageByCamera =
new
Intent("
android.media.action.IMAGE_CAPTURE"
);
// 获取文件
File tempFile =
new File(PATH_ADD +
"
temp.jpg"
);
if (tempFile.exists() &
&
tempFile.isFile()){
tempFile.delete();
}
getImageByCamera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
getImageByCamera.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
startActivityForResult(getImageByCamera,
ChangeMyDataActivityPresenter.REQUEST_CODE_CAPTURE_CAMERA);
} else {
Toast.makeText(getApplicationContext(),
"
请确认已经插入SD卡"
, Toast.LENGTH_LONG).show();
}
break;
}
case R.id.pickPhotoBtn:
//Intent intent =
new Intent(Intent.ACTION_PICK);
//从相册中选取图片
Intent intent =
new Intent("
android.intent.action.GET_CONTENT"
);
//从相册/文件管理中选取图片
intent.setType("
image/*"
);
//相片类型
startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);
break;
case R.id.cancelBtn: {
break;
}
}
}
});
chooseUserImageDialog.showAtLocation(findViewById(R.id.mainLayout),
Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
注解:
- Environment.getExternalStorageState是用来获取外部存储设备的状态, 即SD卡的状态, 这里为大家推荐一篇博文: Android中的Environment.getExternalStorageState使用
- android.media.action.IMAGE_CAPTURE为调用系统照相机
- Itent.ACTION_PICK 、Intent.ACTION_GET_CONTENT
//选择图片 requestCode 返回的标识
Intent innerIntent =
new Intent(Intent.ACTION_GET_CONTENT);
//"
Android.intent.action.GET_CONTENT"
innerIntent.setType(contentType);
//查看类型 String IMAGE_UNSPECIFIED =
"
image/*"
;
Intent wrapperIntent =
Intent.createChooser(innerIntent, null);
((Activity) context).startActivityForResult(wrapperIntent, requestCode);
//视频
Intent innerIntent =
new Intent(Intent.ACTION_GET_CONTENT);
innerIntent.setType(contentType);
//String VIDEO_UNSPECIFIED =
"
video/*"
;
Intent wrapperIntent =
Intent.createChooser(innerIntent, null);
((Activity) context).startActivityForResult(wrapperIntent, requestCode);
//添加音频
Intent innerIntent =
new Intent(Intent.ACTION_GET_CONTENT);
innerIntent.setType(contentType);
//String VIDEO_UNSPECIFIED =
"
video/*"
;
Intent wrapperIntent =
Intent.createChooser(innerIntent, null);
((Activity) context).startActivityForResult(wrapperIntent, requestCode);
//录音
Intent intent =
new Intent(Intent.ACTION_GET_CONTENT);
intent.setType(ContentType.AUDIO_AMR);
//String AUDIO_AMR =
"
audio/amr"
;
intent.setClassName("
com.android.soundrecorder"
,
"
com.android.soundrecorder.SoundRecorder"
);
((Activity) context).startActivityForResult(intent, requestCode);
更详细的使用请看博客: android之Itent.ACTION_PICK Intent.ACTION_GET_CONTENT妙用
- menuWindow.dismiss();
//在点击空白处的时候弹出窗口消失
- 【Android--利用相机或相册截取用户头像(解决了miui无法截取,以及部分机型拍照无返回Uri)】为什么获取的时候有时候拍照获得返回的Uri是一张缩略图?
解决办法:
Intent getImageByCamera = new Intent(" android.media.action.IMAGE_CAPTURE" ); // 获取文件 File tempFile = new File(PATH_ADD + " temp.jpg" ); if (tempFile.exists() & & tempFile.isFile()){ tempFile.delete(); } getImageByCamera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile)); getImageByCamera.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); startActivityForResult(getImageByCamera, ChangeMyDataActivityPresenter.REQUEST_CODE_CAPTURE_CAMERA);
调用系统拍照功能的时候先指定一个文件, 用于相机拍照后的临时文件的输出路径, 这样子即可避免在临时拍照的时候部分机型如( MIUI) 返回缩略图。
Intent intent =
new Intent("
com.android.camera.action.CROP"
);
intent.setDataAndType(uri, "
image/*"
);
intent.putExtra("
crop"
, "
true"
);
//可以裁剪
intent.putExtra("
aspectX"
, 1);
//宽高比例
intent.putExtra("
aspectY"
, 1);
intent.putExtra("
outputX"
, 100);
intent.putExtra("
outputY"
, 100);
intent.putExtra("
return-data"
, true);
intent.putExtra("
output"
, Uri.fromFile(new File("
/mnt/sdcard/temp"
)));
//保存路径
startActivityForResult(intent, RESIZE_REQUEST_CODE);
上述方法中, 裁剪后的图片通过Intent的putExtra(“return-data”,true)方法进行传递, miui系统问题就出在这里, return-data的方式只适用于小图, miui系统默认的裁剪图片可能裁剪得过大, 或对return-data分配的资源不足, 造成return-data失败。
解决思路是: 裁剪后, 将裁剪的图片保存在Uri中, 在onActivityResult()方法中, 再提取对应的Uri图片转换为Bitmap使用。
其实大家直观也能感觉出来, Intent主要用于不同Activity之间通信, 是一种动态的小巧的资源占用, 类似于Http请求中的GET, 并不适用于传递图片之类的大数据。于是当A生成一个大数据要传递给B, 往往不是通过Intent直接传递, 而是在A生成数据的时候将数据保存到C, B再去调用C, C相当于一个转换的中间件。
即以下方法:
File outputImage =
new File(MyConstants.PATH_ADD +
"
crop.jpg"
);
try {
if (outputImage.exists()) {
outputImage.getAbsoluteFile().delete();
}
outputImage.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
Uri userImageUri =
Uri.fromFile(outputImage);
Intent intent =
new Intent("
com.android.camera.action.CROP"
);
intent.setType("
image"
);
intent.setDataAndType(imageUri, "
image/*"
);
// 下面这个crop=
true是设置在开启的Intent中设置显示的VIEW可裁剪
intent.putExtra("
crop"
, true);
intent.putExtra("
scale"
, true);
intent.putExtra("
scaleUpIfNeeded"
, true);
// 去黑边
// aspectX aspectY 是宽高的比例
intent.putExtra("
aspectX"
, 1);
//输出是X方向的比例
intent.putExtra("
aspectY"
, 1);
// outputX outputY 是裁剪图片宽高,
切忌不要再改动下列数字,
会卡死
intent.putExtra("
outputX"
, 500);
//输出X方向的像素
intent.putExtra("
outputY"
, 500);
intent.putExtra("
noFaceDetection"
, true);
intent.putExtra("
return-data"
, false);
//设置为不返回数据
/**
* 此方法返回的图片只能是小图片(
测试为高宽160px的图片)
* 故将图片保存在Uri中,
调用时将Uri转换为Bitmap,
此方法还可解决miui系统不能return data的问题
*/
//intent.putExtra("
return-data"
, true);
//intent.putExtra("
output"
, Uri.fromFile(new File("
/mnt/sdcard/temp"
)));
//保存路径
intent.putExtra(MediaStore.EXTRA_OUTPUT, userImageUri);
//Log.d(TAG, "
reSizeImage() called with: "
+
"
uri =
["
+
userImageUri +
"
]"
);
activity.startActivityForResult(intent, REQUEST_RESIZE_REQUEST_CODE);
return userImageUri;
主界面布局代码
<
?xml version=
"
1.0"
encoding=
"
utf-8"
?>
<
LinearLayout xmlns:android=
"
http://schemas.android.com/apk/res/android"
android:orientation=
"
vertical"
android:id=
"
@
+
id/mainLayout"
android:backgroundTint=
"
@
color/bisque"
android:layout_width=
"
match_parent"
android:layout_height=
"
match_parent"
>
<
TextView
android:textColor=
"
@
color/white"
android:paddingLeft=
"
20dp"
android:gravity=
"
center_vertical|left"
android:background=
"
@
color/brown"
android:textSize=
"
20sp"
android:layout_width=
"
match_parent"
android:layout_height=
"
50dp"
android:text=
"
选择图片"
/>
<
ImageView
android:id=
"
@
+
id/choose_image_image"
android:layout_marginTop=
"
50dp"
android:layout_gravity=
"
center_horizontal"
android:layout_width=
"
100dp"
android:layout_height=
"
100dp"
/>
<
/LinearLayout>
弹出窗口代码:
package com.example.no_clay.demolist.ChooseImage;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.PopupWindow;
import com.example.no_clay.demolist.R;
/**
* Created by 寒 on 2016/6/4.
*/
class SelectPicPopupWindow extends PopupWindow {
private Button takePhotoBtn, pickPhotoBtn, cancelBtn;
private View mMenuView;
@
SuppressLint("
InflateParams"
)
public SelectPicPopupWindow(Context context, View.OnClickListener itemsOnClick) {
super(context);
LayoutInflater inflater =
(LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mMenuView =
inflater.inflate(R.layout.choose_image_layout_dialog_pic, null);
takePhotoBtn =
(Button) mMenuView.findViewById(R.id.takePhotoBtn);
pickPhotoBtn =
(Button) mMenuView.findViewById(R.id.pickPhotoBtn);
cancelBtn =
(Button) mMenuView.findViewById(R.id.cancelBtn);
cancelBtn.setOnClickListener(itemsOnClick);
pickPhotoBtn.setOnClickListener(itemsOnClick);
takePhotoBtn.setOnClickListener(itemsOnClick);
this.setContentView(mMenuView);
this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
this.setFocusable(true);
this.setAnimationStyle(R.style.PopupAnimation);
ColorDrawable dw =
new ColorDrawable(0x80000000);
this.setBackgroundDrawable(dw);
mMenuView.setOnTouchListener(new View.OnTouchListener() {@
Override
@
SuppressLint("
ClickableViewAccessibility"
)
public boolean onTouch(View v, MotionEvent event) {int height =
mMenuView.findViewById(R.id.pop_layout).getTop();
int y =
(int) event.getY();
if (event.getAction() =
=
MotionEvent.ACTION_UP) {
if (y <
height) {
dismiss();
}
}
return true;
}
});
}
}
推荐阅读
- Android Theme.AppCompat 中,你应该熟悉的颜色属性
- 最全的增量更新入门 包含linux端和Android
- (已解决)Eclipse报错(Could not find XXX.apk. 没有Android项目命名. There is no android project named)
- Android-Activity启动流程
- 安卓开源安卓拼图实现,数据驱动,可记录图片位置參数,希望大家有兴趣一起完好!
- 如何在Python中使用Keras和TensorFlow构建垃圾邮件分类器()
- 如何使用Python和Scikit-learn制作语音情感识别器()
- 供数据科学家和机器学习工程师使用的9大Python库合集
- 使用Python与FXCM Broker实现算法交易(详细指南)