Android调用相机与相册的方法
操作流程
点击拍摄
点击头像(我这里使用的是ImageView控件),然后点击拍摄,去申请权限,允许则打开相机 拍摄 然后进去裁剪框 选取合适的位置合适的大小 点击√,即设置成功
效果图
点击相册选择
点击头像,点击相册选择,允许权限则进去图库,选择图片 截取图片,设置成功
效果图
拒绝权限的情况
点击禁止则无操作,勾选禁止后不再提示,则弹出自定义dialog提示框,点击取消即关闭dialog,点击去设置则进入应用设置页面
效果图
功能实现
项目配置
1.先在项目根目录的build.gradle的repositories添加:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
【注意】切记不要跳过这一步,因为XUI目前只发布在jitpack平台上,跳过这一步会导致ERROR: Failed to resolve: com.github.xuexiangjys:XUI:x.x.x错误!!!
2.在build.gradle(:app)的dependencies添加:
// 裁剪相关
implementation 'com.github.yalantis:ucrop:2.2.6'
// XUI dialog相关
implementation 'com.github.xuexiangjys:XUI:1.1.9'
implementation 'com.github.xuexiangjys.XUtil:xutil-core:2.0.0'
// 权限相关
implementation 'com.yanzhenjie:permission:2.0.2'
// 加载图片
implementation 'com.github.bumptech.glide:glide:4.13.1'
3.添加提示dialog样式
如果使用弹出提示的XUI自定义dialog则需要在AndroidManifest.xml中application的主题添加样式
添加以下样式:
<style name="Theme.HeadPhotoTest" parent="XUITheme.Phone">
<!-- 自定义自己的主题样式 -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:textAllCaps">false</item>
</style>
然后Ctrl点进colors.xml添加以下属性:
<color name="colorPrimary">#2196F3</color>
<color name="colorPrimaryDark">#121C4C</color>
<color name="colorAccent">#2196F3</color>
4.添加底部dialog样式
如果需要使用底部弹出dialog则需要在AndroidManifest.xml在application的主题中添加以下样式代码:
<!-- dialog样式 -->
<style name="DialogTheme" parent="@android:style/Theme.Dialog">
<!-- 边框 -->
<item name="android:windowFrame">@null</item>
<!-- 是否浮现在activity之上 -->
<item name="android:windowIsFloating">true</item>
<!-- 半透明 -->
<item name="android:windowIsTranslucent">true</item>
<!-- 无标题 -->
<item name="android:windowNoTitle">true</item>
<item name="android:background">@android:color/transparent</item>
<!-- 背景透明 -->
<item name="android:windowBackground">@android:color/transparent</item>
<!-- 模糊 -->
<item name="android:backgroundDimEnabled">true</item>
<!-- 遮罩层 -->
<item name="android:backgroundDimAmount">0.5</item>
</style>
<!-- dialog的动画 -->
<style name="main_menu_animStyle">
<item name="android:windowEnterAnimation">@drawable/dialog_in_anim</item>
<item name="android:windowExitAnimation">@drawable/dialog_out_anim</item>
</style>
底部dialog弹出动画(dialog_in_anim.xml)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="0"
android:fromYDelta="1000"
android:toXDelta="0"
android:toYDelta="0" />
</set>
底部dialog关闭动画(dialog_out_anim.xml)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="0"
android:toYDelta="1000" />
</set>
5.添加权限
AndroidManifest.xml中加入以下权限代码:
<!-- 请求拍摄权限-->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 读写设备照片及文件-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
6.在AndroidManifest.xml中添加剪切activity活动
如果用到剪切功能需要添加,不用剪切功能则不需要添加
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
代码实现
DialogManager.java
package top.gaojc.util;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import com.xuexiang.xui.widget.dialog.DialogLoader;
import static com.xuexiang.xutil.app.ActivityUtils.startActivity;
public class DialogManager {
// 请求权限对话框
public static void permissionDialog(Context myContext, String str) {
DialogLoader.getInstance().showConfirmDialog(
myContext, "提示", str, "去设置",
(dialog, which) -> {
//引导用户到设置中去进行设置
Intent intent = new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", myContext.getPackageName(), null));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
dialog.dismiss();
},
"取消",
(dialog, which) -> {
dialog.dismiss();
}
);
}
}
dialog_bottom_menu.xml
底部dialog:dialog_bottom_menu.xml
<?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:background="#fff"
android:orientation="vertical">
<TextView
android:id="@+id/tv_take_photo"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="拍摄"
android:textColor="@android:color/background_dark"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/darker_gray" />
<TextView
android:id="@+id/tv_take_pic"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="相册选择"
android:textColor="@android:color/background_dark"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:background="@android:color/darker_gray" />
<TextView
android:id="@+id/tv_cancel"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="取消"
android:textColor="@android:color/background_dark"
android:textSize="16sp" />
</LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/img"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_gravity="center"
android:background="@drawable/img"/>
</FrameLayout>
MainActivity.java
package top.gaojc;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.request.RequestOptions;
import com.gaojc.top.util.DialogManager;
import com.yalantis.ucrop.UCrop;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.runtime.Permission;
import java.io.File;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.content.FileProvider;
public class MainActivity extends Activity {
private ImageView img;
public static final int REQUEST_CODE_CAMERA = 103; //相机
public static final int REQUEST_CODE_ALBUM = 102; //相册
private Uri photoUri;//记录图片地址
private Context context = MainActivity.this;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = findViewById(R.id.img);
img.setOnClickListener(v -> {
// 底部dialog
showBottomDialog();
});
}
// 判断是否有相机权限
private void ifHaveCameraPermission() {
/**
* AndPermission.hasPermissions:判断是否有相对应的权限
* Permission.Group.CAMERA:摄像权限
*/
if (!AndPermission.hasPermissions(this, Permission.Group.CAMERA)) {
/**
* AndPermission:引用权限相关库
* onGranted:允许权限
* onDenied:拒绝权限
*/
// 动态申请权限
AndPermission.with(this).runtime().permission(Permission.Group.CAMERA)
.onGranted(permissions -> {
openCamera();
})
.onDenied(denieds -> {
if (denieds != null && denieds.size() > 0) {
for (int i = 0; i < denieds.size(); i++) {
if (!shouldShowRequestPermissionRationale(denieds.get(i))) {
DialogManager.permissionDialog(this, "没有拍摄和录制权限!");
break;
}
}
}
}).start();
} else {
// 有权限 打开相机
openCamera();
}
}
// 打开相机
private void openCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Build.VERSION.SDK_INT:获取当前系统sdk版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// 适配Android 7.0文件权限,通过FileProvider创建一个content类型的Uri
String fileName = String.format("fr_crop_%s.jpg", System.currentTimeMillis());
File cropFile = new File(this.getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName);
photoUri = FileProvider.getUriForFile(this, this.getPackageName() + ".FileProvider", cropFile);//7.0
} else {
photoUri = getDestinationUri();
}
// android11以后强制分区存储,外部资源无法访问,所以添加一个输出保存位置,然后取值操作
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(intent, REQUEST_CODE_CAMERA);
}
// 判断是否有文件存储权限
private void ifHaveAlbumPermission(Activity activity) {
// Permission.Group.STORAGE:文件存储权限
if (!AndPermission.hasPermissions(activity, Permission.Group.STORAGE)) {
// Request permission
AndPermission.with(activity).runtime().permission(Permission.Group.STORAGE).onGranted(permissions -> {
openAlbum();
}).onDenied(denieds -> {
if (denieds != null && denieds.size() > 0) {
for (int i = 0; i < denieds.size(); i++) {
if (!activity.shouldShowRequestPermissionRationale(denieds.get(i))) {
DialogManager.permissionDialog(activity, "没有访问存储权限!");
break;
}
}
}
}).start();
} else {
openAlbum();
}
}
// 打开相册
private void openAlbum() {
Intent intent = new Intent();
// intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);//支持多选图片
intent.setType("image/*");
intent.setAction("android.intent.action.GET_CONTENT");
intent.addCategory("android.intent.category.OPENABLE");
startActivityForResult(intent, REQUEST_CODE_ALBUM);
}
@RequiresApi(api = Build.VERSION_CODES.Q)
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case REQUEST_CODE_ALBUM:
doCrop(data.getData());
break;
case REQUEST_CODE_CAMERA:
doCrop(photoUri);
break;
case UCrop.REQUEST_CROP:
// 加载圆形图片
Glide.with(context).load(UCrop.getOutput(data)).apply(RequestOptions.bitmapTransform(new CircleCrop())).into(img);
// Glide.with(context).load(UCrop.getOutput(data)).into(img);//方形图像
break;
}
}
if (resultCode == UCrop.RESULT_ERROR) {
final Throwable cropError = UCrop.getError(data);
}
}
// 裁剪方法
private void doCrop(Uri data) {
UCrop.of(data, getDestinationUri())//当前资源,保存目标位置
.withAspectRatio(1f, 1f)//宽高比
.withMaxResultSize(500, 500)//宽高
.start(this);
}
private Uri getDestinationUri() {
String fileName = String.format("fr_crop_%s.jpg", System.currentTimeMillis());
File cropFile = new File(this.getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName);
return Uri.fromFile(cropFile);
}
private void showBottomDialog() {
// 使用Dialog、设置style
final Dialog dialog = new Dialog(this, R.style.DialogTheme);
// 设置布局
View view = View.inflate(this, R.layout.dialog_bottom_menu, null);
dialog.setContentView(view);
Window window = dialog.getWindow();
// 设置弹出位置
window.setGravity(Gravity.BOTTOM);
// 设置弹出动画
window.setWindowAnimations(R.style.main_menu_animStyle);
// 设置对话框大小
window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
dialog.show();
dialog.findViewById(R.id.tv_take_photo).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 判断是否有相机权限
ifHaveCameraPermission();
dialog.dismiss();
}
});
dialog.findViewById(R.id.tv_take_pic).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 判断是否有文件存储权限
ifHaveAlbumPermission((Activity) context);
dialog.dismiss();
}
});
dialog.findViewById(R.id.tv_cancel).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dialog.dismiss();
}
});
}
}
不使用剪切框(点击拍摄直接替换)
把这个剪切方法注释掉,onActivityResult回调中的代码修改为以下方式即可
使用方形图片方法
圆形图片代码注释,方形图像取消注释即可
多选图片
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);