Android调用相机与相册的方法

2022-08-07 12:43:08 浏览数 (1)

Android调用相机与相册的方法

  • 操作流程
    • 点击拍摄
      • 效果图
    • 点击相册选择
      • 效果图
    • 拒绝权限的情况
      • 效果图
  • 功能实现
    • 项目配置
      • 1.先在项目根目录的build.gradle的repositories添加:
      • 2.在build.gradle(:app)的dependencies添加:
      • 3.添加提示dialog样式
      • 4.添加底部dialog样式
        • 底部dialog弹出动画(dialog_in_anim.xml)
        • 底部dialog关闭动画(dialog_out_anim.xml)
      • 5.添加权限
      • 6.在AndroidManifest.xml中添加剪切activity活动
    • 代码实现
      • DialogManager.java
      • dialog_bottom_menu.xml
      • activity_main.xml
      • MainActivity.java
        • 不使用剪切框(点击拍摄直接替换)
        • 使用方形图片方法
          • 效果图
  • ~~~~~~~~~~~~~~~~~~~
  • 如有遗漏或有任何问题可添加博主微信反馈

操作流程

点击拍摄

点击头像(我这里使用的是ImageView控件),然后点击拍摄,去申请权限,允许则打开相机 拍摄 然后进去裁剪框 选取合适的位置合适的大小 点击√,即设置成功

效果图

点击相册选择

点击头像,点击相册选择,允许权限则进去图库,选择图片 截取图片,设置成功

效果图

拒绝权限的情况

点击禁止则无操作,勾选禁止后不再提示,则弹出自定义dialog提示框,点击取消即关闭dialog,点击去设置则进入应用设置页面

效果图

功能实现

项目配置

1.先在项目根目录的build.gradle的repositories添加:

代码语言:javascript复制
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添加:

代码语言:javascript复制
	// 裁剪相关
    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的主题添加样式

添加以下样式:

代码语言:javascript复制
<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添加以下属性:

代码语言:javascript复制
<color name="colorPrimary">#2196F3</color>
<color name="colorPrimaryDark">#121C4C</color>
<color name="colorAccent">#2196F3</color>

4.添加底部dialog样式

如果需要使用底部弹出dialog则需要在AndroidManifest.xml在application的主题中添加以下样式代码:

代码语言:javascript复制
	<!-- 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)
代码语言:javascript复制
<?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)
代码语言:javascript复制
<?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中加入以下权限代码:

代码语言:javascript复制
	<!-- 请求拍摄权限-->
    <uses-permission android:name="android.permission.CAMERA" />
    <!-- 读写设备照片及文件-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

6.在AndroidManifest.xml中添加剪切activity活动

如果用到剪切功能需要添加,不用剪切功能则不需要添加

代码语言:javascript复制
	<activity
        android:name="com.yalantis.ucrop.UCropActivity"
        android:screenOrientation="portrait"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar" />

代码实现

DialogManager.java

代码语言:javascript复制
package com.gaojc.top.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

代码语言:javascript复制
<?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

代码语言:javascript复制
<?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

代码语言:javascript复制
package com.gaojc.top;

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.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回调中的代码修改为以下方式即可

使用方形图片方法

圆形图片代码注释,方形图像取消注释即可

效果图

0 人点赞