Android 拍照以及相册中选择(适配高版本)————上传头像并裁剪(一)

news2024/11/24 7:08:52

在这里插入图片描述

前言

       在项目研发中,相信大家都遇到过给用户增加头像照片的需求。

       随着手机版本的不断更新,android 8、android 9、android 10、android 12、android 13、鸿蒙系统等等;遇到这个功能需求,大家肯定会想,“这还不好写? 之前就已经写过了。” 把老项目跑了一遍之后发现无法运行。要不大多数就会出现奔溃的情况!

       这也就遇到常见的 高版本适配情况,以及针对不同版本该如何处理?

       碰到这种情况也不要慌张,博主将为大家推出两篇热乎连载篇。从两个不同开发场景下,来给大家分享两篇文章,来更加详细的了解该如何去实现?【特此来记录

       本篇将为大家详细讲解如何调用摄像头拍照 & 选择相册,并裁剪图片

效果

实测android 8、android 9、android 11、android 13、鸿蒙系统均有效;
手机机型分别为OPPO、华为、VIVO手机。

对于效果演示,将单独拿出两个来举例:

  • VIVO android 13
  • 华为 鸿蒙系统2.0.1
vivo华为

功能

  1. 动态申请拍照,读,写权限
  2. 自定义弹出框
  3. 调用系统相机拍照
    3.1 调用系统相机申请拍照权限回调
    3.2 拍照完成回调
  4. 自动获取sdk权限
    4.1 访问相册完成回调

具体实现

.gradle配置文件:

在这里插入图片描述

AndroidManifest文件:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<provider
      android:name="androidx.core.content.FileProvider"
      android:authorities="com.harry.takepicture.provider"
      android:exported="false"
      android:grantUriPermissions="true">
          <meta-data
             android:name="android.support.FILE_PROVIDER_PATHS"
             android:resource="@xml/filepaths" />
</provider>

filepaths.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <paths>
        <external-path
            name="camera_photos"
            path="" />
    </paths>
    <external-path name="rc_external_path" path="."/>

</paths>
/**
 * @author 拉莫帅
 * @date 2023/4/01
 * @address
 * @Desc TakePicture 上传头像
 */
public class MainActivity extends BaseActivity implements View.OnClickListener {
    public static String[] permission = {
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.CAMERA};

    private CircleImg img;
    private View view;

    private String BaseUrl = "";

    private Uri newUri;
    private File outputImage;
    private Uri cropImageUri;
    private File fileCropUri;//裁剪的照片
    private Uri imageUri;//拍照所得到的图像的保存路径
    private static final int OUTPUT_X = 295;
    private static final int OUTPUT_Y = 413;
    private static final int CODE_GALLERY_REQUEST = 0xa0;
    private static final int CODE_CAMERA_REQUEST = 0xa1;
    private static final int CODE_RESULT_REQUEST = 0xa2;
    private static final int REQUESTCODE_CUTTING = 0xa3;
    private static final int CAMERA_PERMISSIONS_REQUEST_CODE = 0x03;
    private static final int STORAGE_PERMISSIONS_REQUEST_CODE = 0x04;
    
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStatusBg(1);
        AppUtils.requestPermission(permission);

        img = findViewById(R.id.userinfo_iv_head);
        img.setOnClickListener(this);
    }

    
    protected View addContentLayout() {
        view = getLayoutInflater().inflate(R.layout.activity_main, contentLayout, false);
        return view;
    }

    
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.userinfo_iv_head:
                select();
                break;
            case R.id.rl_head_camera:
                takePhoto();
                AppUtils.dismiss();
                break;
            case R.id.rl_head_photo:
                autoObtainStoragePermission();
                AppUtils.dismiss();
                break;
            case R.id.rl_head_cancel:
                AppUtils.dismiss();
                break;
        }
    }

    private void select() {        
        AppUtils.selectPhoto(MainActivity.this, R.layout.dialog_head, R.layout.activity_main, this);
    }

    /**
     * 拍照
     *
     * @param
     */
    private void takePhoto() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
                ToastUtils.showShort(this, "您已经拒绝过一次");
            }
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSIONS_REQUEST_CODE);
        } else {//有权限直接调用系统相机拍照
            if (AppUtils.hasSdcard()) {
                    outputImage = new File(Environment.getExternalStorageDirectory().getPath(), System.currentTimeMillis() + ".jpg");

                    //通过FileProvider创建一个content类型的Uri
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        imageUri = FileProvider.getUriForFile(this, "com.harry.takepicture.provider", outputImage);
                    } else {
                        imageUri = Uri.fromFile(outputImage);
                    }

                    PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);             
            } else {
                ToastUtils.showShort(this, "设备没有SD卡!");
            }
        }
    }

    
    public void onRequestPermissionsResult(int requestCode,  String[] permissions,  int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        switch (requestCode) {
            //调用系统相机申请拍照权限回调
            case CAMERA_PERMISSIONS_REQUEST_CODE: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (AppUtils.hasSdcard()) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                            imageUri = FileProvider.getUriForFile(MainActivity.this, "com.harry.takepicture.provider", outputImage);
                        } else {
                            imageUri = Uri.fromFile(outputImage);
                        }
                        
                        PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);                   
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                } else {
                    ToastUtils.showShort(this, "请允许打开相机!!");
                }
                break;
            }
        }
    }

    /**
     * 自动获取sdk权限
     */
    private void autoObtainStoragePermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSIONS_REQUEST_CODE);
        } else {
            PhotoUtils.openPic(this, CODE_GALLERY_REQUEST);
        }
    }

    
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == RESULT_OK) {
            fileCropUri = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");
            switch (requestCode) {
                //拍照完成回调
                case CODE_CAMERA_REQUEST:
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        Uri contentUri = FileProvider.getUriForFile(this, "com.harry.takepicture.provider", outputImage);
                        cropPhoto(contentUri);
                    } else {
                        imageUri = Uri.fromFile(outputImage);
                        cropPhoto(imageUri);
                    }
                //访问相册完成回调
                case CODE_GALLERY_REQUEST:
                    if (AppUtils.hasSdcard()) {
                        cropImageUri = Uri.fromFile(fileCropUri);
                        if (data == null) {
                            return;
                        } else {
                            newUri = getUri(data);
                        }
                        PhotoUtils.cropImageUri(this, newUri, cropImageUri, 1, 1, OUTPUT_X, OUTPUT_Y, CODE_RESULT_REQUEST);
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                    break;
                case REQUESTCODE_CUTTING:
                    if (data != null) {
                        setPicToView(data);
                    }
                    break;
                case CODE_RESULT_REQUEST:
                    String a = cropImageUri.getPath();
                    Log.e("tb", "a---" + a);
                    Bitmap bitmap = PhotoUtils.getBitmapFromUri(cropImageUri, this);
                    if (bitmap != null) {
                        File file = new File(a);
                        Log.e("tb", "file--------------------------" + file);
                        BaseUrl = Base64Utils.getImageStr(file);
                        Log.e("tb", "BaseUrl--------------------------" + BaseUrl);

                        showImages(bitmap, a);
                    }
                    break;
                default:
            }
        }
    }

    private void setPicToView(Intent picdata) {
        Bundle extras = picdata.getExtras();
        if (extras != null) {
            // 取得SDCard图片路径做显示
            Bitmap photo = extras.getParcelable("data");
            String saveFile = FileUtil.saveFile(this, "crop", photo);

            if (photo != null) {
                File file = new File(saveFile);
                Log.e("tb", "file--------------------------" + file);
                BaseUrl = Base64Utils.getImageStr(file);
                Log.e("tb", "BaseUrl--------------------------" + BaseUrl);

                showImages(photo, saveFile);
            }
        }
    }

	/**
     * 裁剪
     * 
     * @param uri
     */
    private void cropPhoto(Uri uri) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);

        intent.putExtra("outputX", 300);
        intent.putExtra("outputY", 300);
        intent.putExtra("return-data", true);
        Log.e("tag", "intent====" + intent);

        startActivityForResult(intent, REQUESTCODE_CUTTING);
    }

	/**
     * 展示
     * 
     * @param bitmap
     * @param urlpath
     */
    private void showImages(Bitmap bitmap, String urlpath) {
        Drawable drawable = new BitmapDrawable(null, bitmap);
        Log.e("tag", "urlPath====" + urlpath);
        img.setImageDrawable(drawable);
    }

    /**
     * 解决手机上获取图片路径为null的情况
     *
     * @param intent
     * @return
     */
    public Uri getUri(android.content.Intent intent) {
        Uri uri = intent.getData();
        String type = intent.getType();
        if (uri.getScheme().equals("file") && (type.contains("image/"))) {
            String path = uri.getEncodedPath();
            if (path != null) {
                path = Uri.decode(path);
                ContentResolver cr = this.getContentResolver();
                StringBuffer buff = new StringBuffer();
                buff.append("(").append(MediaStore.Images.ImageColumns.DATA).append("=")
                        .append("'" + path + "'").append(")");
                Cursor cur = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        new String[]{MediaStore.Images.ImageColumns._ID},
                        buff.toString(), null, null);
                int index = 0;
                for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
                    index = cur.getColumnIndex(MediaStore.Images.ImageColumns._ID);
                    // set _id value
                    index = cur.getInt(index);
                }
                if (index == 0) {
                    // do nothing
                } else {
                    Uri uri_temp = Uri
                            .parse("content://media/external/images/media/"
                                    + index);
                    if (uri_temp != null) {
                        uri = uri_temp;
                    }
                }
            }
        }
        return uri;
    }
}

总结

       到这里就结束了。看到这里,关于上传头像的具体流程也已经清楚,最主要的代码也已经给大家粘贴了过来。

       感兴趣的小伙伴们,大家赶快去测试一下吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/467553.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“双碳”目标下二氧化碳地质封存技术应用前景及模型构建实践方法

二氧化碳地质封存技术起步较晚&#xff0c;目前仍没有一套相对完整的行业规范&#xff1b;且就该技术而言&#xff0c;涉及环节众多&#xff0c;理论相对复杂&#xff0c;对于行业的新入局者不太友好。因此&#xff0c;结合时代背景&#xff0c;我们首次尝试对二氧化碳地质封存…

【裸金属服务器】安装VMware ESXi

官方安装操作ESXi地址 一、虚拟化服务器分类&#xff1a; 寄居架构&#xff08;Hosted Architecture&#xff09;和裸金属架构&#xff08;Bare Metal Architecture&#xff09;。 1、寄居架构&#xff08;Hosted Architecture&#xff09;&#xff1a;在操作系统之上安装和运…

8.系统日志

1.api访问日志 对应数据库 拦截器 拦截逻辑 ApiAccessLogFilter类的createApiAccessLog方法 buildApiAccessLogDTO方法就是完善实体类&#xff0c;把接口执行时长之类的填充完整。 然后就是保存日志到infra_api_access_log数据库。 过滤器注册生效 2.api错误日志 对应数…

Windows 程序开机自启动速度优化,为什么腾讯会议自启动速度那么高?

目录 一、问题的说明和定义 二、问题的分析 1.问题初步分析 2.详细的分析&#xff1a; 2.1Windows常见的自启动方式 2.2Windows常见的自启动方式的细节分析 三、问题的解决方案 1、为什么腾讯会议Rooms那么快 2.我们是否可以跟腾讯会议一样快 一、问题的说明和定义 这…

Vue之插件的定义和使用

概述 学习本文之前&#xff0c;我们需要弄清楚何为插件&#xff1f;插件其实就是一段扩展程序&#xff0c;主要目的是用于扩展功能。就比如Idea家族和VSCode家族的插件&#xff0c;它们也是一段扩展程序&#xff0c;将其安装到IDE中就可以使用插件里面实现的功能了&#xff0c…

SCADA平台的HMI功能

01 前言 虹科Panorama SCADA平台支持桌面HMI、Web HMI和移动HMI的功能。桌面HMI主要是在桌面工作站实现数据可视化&#xff0c;能够获取到最全面的数据信息以及实现功能&#xff1b;Web HMI可以通过在软件中添加Web HMI服务器&#xff0c;运行程序后&#xff0c;可以在Web 客户…

HTML5基础知识总结总结(详细,附带源代码)

HTML5基础知识 一&#xff1a;前言二&#xff1a; HTML基本结构。三&#xff1a;基本标签3.1 h标签3.2 p标签3.3 hr标签3.4 br标签3.5 strong标签与em标签3.6 特殊符号3.7 运行效果 三&#xff1a;图像标签四&#xff1a;链接标签五&#xff1a;列表六&#xff1a;表格七&#…

Allegro PCB后处理和生产文件导出

Allegro PCB后处理&#xff0c;主要是完成线路设计以后&#xff0c;输出生产文件之前的处理。部分是看教程做的记录&#xff0c;方便以后自己参考。 教程&#xff1a; [小哥Cadence Allegro 132讲字幕版PCB视频教程]_哔哩哔哩_bilibili 感觉关键是多看右边Options菜单&#xf…

【15】SCI易中期刊推荐——电子电气 | 仪器仪表(中科院4区)

💖💖>>>加勒比海带,QQ2479200884<<<💖💖 🍀🍀>>>【YOLO魔法搭配&论文投稿咨询】<<<🍀🍀 ✨✨>>>学习交流 | 温澜潮生 | 合作共赢 | 共同进步<<<✨✨ 📚📚>>>人工智能 | 计算机视觉…

[NISACTF 2022]level-up

[NISACTF 2022]level-up f12 发现提示disallow 也就是不允许的想到robots.txt LEVEL_2 <?php //here is level 2 error_reporting(0); #屏蔽报错信息 include "str.php"; #包含str.php这个页面 if (isset($_POST[array1]) && isset($_POST[arr…

巧用千寻位置GNSS软件|如何快速完成道路桥涵放样

道路桥涵放样主要解决道路施工中正交、斜交涵洞的测量&#xff0c;正交涵洞放样是中心线的定线放样&#xff1b;斜交涵洞放养是涵洞中心线与线路成一固定夹角的情况下的放样。 那么如何运用千寻位置GNSS软件实现道路桥涵放样呢&#xff1f;下面为各位一一介绍。 点击【测量】-&…

【移动端网页布局】移动端网页布局基础概念 ⑨ ( webkit 内核 | 移动端网页 CSS 初始化 - normalize.css )

文章目录 一、webkit 内核二、移动端网页 CSS 初始化 - normalize.css 一、webkit 内核 移动端浏览器 都是 基于 webkit 内核的 , QQ 浏览器 / 百度 / Safari / UC 都是基于 webkit 内核的 ; 移动端网页布局需要 兼容 普通浏览器 与 webkit 浏览器 ; webkit 内核浏览器 对 HT…

Ubuntu18 更换 apt 源为阿里云

Step1. 备份 list 文件 进入对应文件夹&#xff0c;用管理员权限&#xff0c;执行复制操作&#xff1a; cd /etc/apt/ sudo cp sources.list sources.list.bak Step2. 修改 list 文件 通过管理员权限&#xff0c;使用 vim 进行修改&#xff1a; sudo vim sources.list 将…

【Pytorch】六行代码实现:特征图提取与特征图可视化

前言 之前记录过特征图的可视化&#xff1a;Pytorch实现特征图可视化&#xff0c;当时是利用IntermediateLayerGetter 实现的&#xff0c;但是有很大缺陷&#xff0c;只能获取到一级的子模块的特征图输出&#xff0c;无法获取内部二级子模块的输出。今天补充另一种Pytorch官方…

ChatGPT如何写作-ChatGPT写作程序

ChatGPT如何写作 ChatGPT是一款自然语言处理模型&#xff0c;它无法像人类一样进行“写作”。但是&#xff0c;您可以利用ChatGPT的生成文本功能来帮助您生成文字。以下是一些使用ChatGPT写作的建议&#xff1a; 确定主题和目标受众。在开始写作之前&#xff0c;请确保您清楚知…

凝心聚力,携“源”出海:开源社顾问委员会2023年第一季度会议圆满举办!

2023 年 3 月 25 日&#xff0c;开源社顾问委员会&#xff08;以下简称"顾问委员会"&#xff09;第一季度会议在北京圆满召开。这是顾问委员会自 2018 年成立以来的第 17 次全体委员会议。 为增进顾问委员会成员交流&#xff0c;加强开源社社区建设&#xff0c;实现开…

第五章 资源包使用

游戏开发中会大量使用模型文件&#xff0c;图片文件&#xff0c;这些资源都需要事先导入到项目中去。导入的方式非常简单&#xff0c;将这些文件直接复制到项目中的Assets目录下即可。Unity 会在文件添加到 Assets 文件夹时自动检测到这些文件并同步显示在Project视图中。 Uni…

内分泌失调对身体有什么影响?

体内各种荷尔蒙的平衡&#xff0c;可以维持内分泌的稳定&#xff0c;当生活节奏被打乱&#xff0c;就会导致熬夜、入睡困难、压力过大、不按时就餐、久坐、情绪不稳定等。 对此&#xff0c;内分泌失调都是不小的问题&#xff0c;都是会影响身体的各个部位的。 内分泌对身体有什…

【U8+】用友U8+产品-操作系统、数据库、浏览器推荐支持一览表

【业务场景】 大家平时在服务、实施过程中&#xff0c; 经常被问到各个版本的产品支持什么版本操作系统、数据库、浏览器&#xff1f; 根据各个版本发版说明&#xff0c; 总结了操作系统、数据库、浏览器推荐使用一览表。 软件版本与电脑操作系统版本相辅相承&#xff0c; 一方…

Redis 缓存穿透、缓存雪崩、缓存击穿

缓存穿透 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样缓存永远不会生效&#xff0c;这些请求都会打到数据库。 常见的解决方案有两种&#xff1a; 缓存空对象 优点&#xff1a;实现简单&#xff0c;维护方便 缺点&#xff1a; 额外的内存消耗 可…