前段时间要做一个头像选取的功能,本来想使用第三方库,结果在其他的机型好好的,在小米的一个机型上直接崩溃了。
这果断的不能忍啊,咱们自己来实现调用系统相机、相册选取图片的功能,然后进行系统裁剪返回,结果发现刚出一坑又进
入一大坑,下面是填坑指南。
以下代码亲测在小米,华为,oppo等主流机型上兼容,并且兼容android 7.0的 FileProvider。
实现效果:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final int ACTION_TYPE_PHOTO = 0;
private final int CAMERA = 10;
private final int ALBUM = 20;
private final int CUPREQUEST = 50;
private CircleImageView mCivMainHead;
private PopupWindow mPopupWindow;
private String picPath;
private File mOutImage;
private Uri mImageUri;
private Uri uritempFile;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCivMainHead = (CircleImageView) findViewById(R.id.civ_main_head);
mCivMainHead.setOnClickListener(this);
//申请权限
MPermissions.requestPermissions(MainActivity.this,
ACTION_TYPE_PHOTO,
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.civ_main_head:
initPhotoTypePop();
break;
default:
break;
}
}
/**
* 初始化选择头像的pop
*/
private void initPhotoTypePop() {
mPopupWindow = showBotoomSmallWidthPopup(MainActivity.this,
R.layout.popu_photo, mCivMainHead);
View contentView = mPopupWindow.getContentView();
final TextView mobile_phones = (TextView) contentView.findViewById(R.id.mobile_phones);
final TextView local_photo = (TextView) contentView.findViewById(R.id.local_photo);
final TextView cancel = (TextView) contentView.findViewById(R.id.cancel);
mobile_phones.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
setMobilePhones();
}
});
local_photo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
setLocalPhoto();
}
});
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mPopupWindow.dismiss();
}
});
}
/**
* 相册
*/
private void setLocalPhoto() {
if (mPopupWindow != null && mPopupWindow.isShowing()) {
mPopupWindow.dismiss();
}
Intent albumIntent = new Intent(Intent.ACTION_PICK, null);
albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(albumIntent, ALBUM);
}
/**
* 拍照
*/
private void setMobilePhones() {
if (mPopupWindow !=null && mPopupWindow.isShowing()){
mPopupWindow.dismiss();
}
//获得项目缓存路径
String sdPath = getExternalCacheDir().getPath();
//根据时间随机生成图片名
String photoName = new DateFormat().format("yyyyMMddhhmmss",
Calendar.getInstance(Locale.CHINA)) + ".jpg";
picPath = sdPath + "/" + photoName;
mOutImage = new File(picPath);
//如果是7.0以上 那么就把uir包装
if (Build.VERSION.SDK_INT >= 24) {
mImageUri = FileProvider.getUriForFile(MainActivity.this, "com.test.FileProvider", mOutImage);
} else {
//否则就用老系统的默认模式
mImageUri = Uri.fromFile(mOutImage);
}
//启动相机
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
startActivityForResult(intent, CAMERA);
}
/**
* 选择图片后的回调
*
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) {
return;
}
switch (requestCode) {
// 裁剪相机照片
case CAMERA:
setCropPhoto();
break;
//裁剪本地相册
case ALBUM:
Uri data1 = data.getData();
if (data1 != null) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
picPath = data1.toString();
} else {
picPath = data1.getPath();
}
// Uri --> Path
if (picPath.contains("content://")) {
picPath = PathContentUtils.getFilePathFromContentUri(data1, getContentResolver());
}
mOutImage = new File(picPath);
setCropPhoto();
}
break;
//裁剪完成
case CUPREQUEST:
if (data == null) {
return;
}
Bundle extras = data.getExtras();
String s;
if (Build.MANUFACTURER.contains("Xiaomi")){
if (uritempFile !=null){
s = uritempFile.getPath();
}else {
s = "";
}
}else {
if (extras != null){
Bitmap photo = extras.getParcelable("data");
s = FileUtils.saveBitmap(photo);
}else {
s ="";
}
}
if(!TextUtils.isEmpty(s)){
Bitmap bitmap = BitmapFactory.decodeFile(s);
mCivMainHead.setImageBitmap(photo);
}
break;
default:
break;
}
}
private void setCropPhoto() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//如果是7.0剪裁图片 同理 需要把uri包装
//通过FileProvider创建一个content类型的Uri
Uri inputUri = FileProvider.getUriForFile(MainActivity.this,
"com.test.FileProvider", mOutImage);
startPhotoZoom(inputUri);//设置输入类型
} else {
Uri inputUri = Uri.fromFile(mOutImage);
startPhotoZoom(inputUri);
}
}
//裁剪
private void startPhotoZoom(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
//sdk>=24
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//去除默认的人脸识别,否则和剪裁匡重叠
intent.putExtra("noFaceDetection", false);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
// 设置裁剪
intent.putExtra("crop", "true");
// aspectX aspectY 宽高的比例
//华为特殊处理 不然会显示圆
if (android.os.Build.MODEL.contains("HUAWEI")) {
intent.putExtra("aspectX", 9998);
intent.putExtra("aspectY", 9999);
} else {
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
}
// outputX outputY 是裁剪图片宽高
intent.putExtra("outputX", 200);
intent.putExtra("outputY", 200);
//miui系统 特殊处理 return-data的方式只适用于小图。
if (Build.MANUFACTURER.contains("Xiaomi")){
//裁剪后的图片Uri路径,uritempFile为Uri类变量
uritempFile = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "tt.jpg");
intent.putExtra(MediaStore.EXTRA_OUTPUT, uritempFile);
}else {
intent.putExtra("return-data", true);
}
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
startActivityForResult(intent, CUPREQUEST);
}
/**
* 从底部弹出pop
*/
public static PopupWindow showBotoomSmallWidthPopup(final Activity activity, int layoutId, View view) {
View convertView = LayoutInflater.from(activity)
.inflate(layoutId, null);
PopupWindow popupWindow = new PopupWindow(convertView, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
popupWindow.setAnimationStyle(R.style.popup_bottom_style);
popupWindow.setOutsideTouchable(true);
popupWindow.setFocusable(true);
ColorDrawable cd = new ColorDrawable(000000);
popupWindow.setBackgroundDrawable(cd);
popupWindow.showAtLocation(view, Gravity.BOTTOM, 0, 0);
setBackgroundAlpha(activity, 0.15f);
popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
setBackgroundAlpha(activity, 1.0f);
}
});
return popupWindow;
}
/**
* 弹出popwindow 周围变暗
*
* @param activity
* @param alpha
*/
public static void setBackgroundAlpha(Activity activity, float alpha) {
WindowManager.LayoutParams lp = activity.getWindow()
.getAttributes();
lp.alpha = alpha;
activity.getWindow()
.setAttributes(lp);
}
}
FileProvider 应该在清单文件里进行注册:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.test.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/rc_file_path" />
</provider>
</application>
记得加上权限:
<uses-permission android:name="com.oppo.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.oppo.launcher.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.CAMERA"/>
推荐使用mpermission进行运行时权限管理,使用到的第三方库:
//运行时权限
compile 'com.zhy:mpermission-api:1.0.0'
//圆形头像
compile 'de.hdodenhof:circleimageview:2.1.0'