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

在这里插入图片描述

前言

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

       随着手机版本的不断更新,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" />
<providerandroid:name="androidx.core.content.FileProvider"android:authorities="com.harry.takepicture.provider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/filepaths" />
</provider>

filepaths.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<paths><paths><external-pathname="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类型的Uriif (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 valueindex = 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;}
}

总结

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

       完整版源码下载地址:Android + <调用相机拍照 & 选择相册> + 数码相机

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++文件操作(2)

文件操作&#xff08;2&#xff09; 1.二进制模式读取文本文件2.使用二进制读写其他类型内容3.fstream类4.文件的随机存取文件指针的获取文件指针的移动 1.二进制模式读取文本文件 用二进制方式打开文本存储的文件时&#xff0c;也可以读取其中的内容&#xff0c;因为文本文件…

RabbitMQ快速上手

首先他的需求实在什么地方。我美哟明显的感受到。 它给我的最大感受就是脱裤子放屁——多此一举&#xff0c;的感觉。 他将信息发送给服务端中间件。在由MQ服务器发送消息。 服务器会监听消息。 但是它不仅仅局限于削峰填谷和稳定发送信息的功能&#xff0c;它还有其他重要…

15.Golang中的反射机制及应用

目录 概述实践基本应用复杂应用 结束 概述 Golang中的反射用法还是比较简单的 reflect.TypeOf(arg)reflect.ValueOf(arg) 实践 基本应用 package mainimport ("fmt""reflect" )func reflectNum(arg interface{}) {fmt.Println("type ", re…

十分钟快速上手Spring Boot与微信小程序API接口的调用,快速开发小程序后端服务

1.1 微信小程序API接口介绍 微信小程序API接口是连接小程序前端与后端服务器的桥梁&#xff0c;它提供了丰富的功能接口&#xff0c;包括用户信息、支付、模板消息、数据存储等。这些API接口能够满足开发者在小程序中实现各种复杂业务逻辑的需求。 用户信息接口 用户信息接口…

全流程机器视觉工程开发(四)PaddleDetection C++工程化应用部署到本地DLL以供软件调用

前言 我们之前跑了一个yolo的模型&#xff0c;然后我们通过PaddleDetection的库对这个模型进行了一定程度的调用&#xff0c;但是那个调用还是基于命令的调用&#xff0c;这样的库首先第一个不能部署到客户的电脑上&#xff0c;第二个用起来也非常不方便&#xff0c;那么我们可…

【C++干货基地】C++引用与指针的区别:深入理解两者特性及选择正确应用场景

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…

MYSQL的配置和安装

下载安装 打开官网 MYSQL官网 点击DOWNLOADS 滑到最低下点击&#xff1a;MYSQL Community(GPL) Downlads 点击Download Archives 点击MySQL Community Server进入网站 选择相应版本下载&#xff0c;这里选择的是5.7.24版本,x86 64位【按需选择】 下载解压 配置文件…

GitLab16.8配置webhooks、Jenkins2.4配置GitLab插件实现持续集成、配置宝塔面板实现持续部署(其三)

看本篇文章的前提是已经部署完GItlab和Jenkins服务器&#xff0c;已经可以手动构建成功&#xff0c;并且经过了很多次实践&#xff0c;对这两款软件基本熟悉。 建议大家按以下顺序看 前端自动化&#xff08;其一&#xff09;部署gitlab 前端自动化&#xff08;其二&#xff0…

LeetCode--171

171. Excel 表列序号 给你一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如&#xff1a; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ... 示例 1: 输入: columnTitle "A" 输出:…

设计模式⑩ :用类来实现

文章目录 一、前言二、Command 模式1. 介绍2.应用3. 总结 三、Interpreter 模式1. 介绍2. 应用3. 总结 参考文章 一、前言 有时候不想动脑子&#xff0c;就懒得看源码又不像浪费时间所以会看看书&#xff0c;但是又记不住&#xff0c;所以决定开始写"抄书"系列。本系…

【JS逆向实战-入门篇】某gov网站加密参数分析与Python算法还原

文章目录 1. 写在前面2. 请求分析3. 断点分析4. 算法还原 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向感兴趣的朋…

PPT、PDF全文档翻译相关产品调研笔记

主要找一下是否有比较给力的全文档翻译 文章目录 1 百度翻译2 小牛翻译3 腾讯交互翻译4 DeepL5 languagex6 云译科技7 快翻:qtrans8 simplifyai9 officetranslator10 火山引擎翻译-无文档翻译1 百度翻译 地址: https://fanyi.baidu.com/ 配套的比较完善,对于不同行业也有区…

【大厂AI课学习笔记】1.3 人工智能产业发展(2)

&#xff08;注&#xff1a;腾讯AI课学习笔记。&#xff09; 1.3.1 需求侧 转型需求&#xff1a;人口红利转化为创新红利。 场景丰富&#xff1a;超大规模且多样的应用场景。主要是我们的场景大&#xff0c;数据资源丰富。 抗疫加速&#xff1a;疫情常态化&#xff0c;催生新…

DataX介绍

一、介绍 DataX 是一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 github地址 详细文档 操作手册 支持数据框架如下&#xff1a; 架构 Reader&#xff1…

干货!收藏!一文讲清楚数据治理到底是什么?

数据治理的两个目标&#xff1a;一个是提质量&#xff0c;一个是控安全。通过业务流程优化&#xff0c;规范数据从产生、处理、使用到销毁的整个生命周期&#xff0c;使得数据在各阶段、各流程环节安全可控&#xff0c;合规使用。 数据治理治的是“数据”吗&#xff1f; 数据是…

Ubuntu搭建国标平台wvp-GB28181-pro

目录 简介安装和编译1.查看操作系统信息2.安装最新版的nodejs3.安装java环境4.安装mysql5.安装redis6.安装编译器7.安装cmake8.安装依赖库9.编译ZLMediaKit9.1.编译结果说明 10.编译wvp-GB28181-pro10.1.编译结果说明 配置1.WVP-PRO配置文件1.1.Mysql数据库配置1.2.REDIS数据库…

GPT-5的功能界面曝光。。。

最近网络上流传的照片是否真实尚不可知&#xff0c;我们需要进一步的核实与分析。 GPT-5的预期发布已经引起了业界的极大关注。根据Roemmele的透露&#xff0c;GPT-5将是一个革命性的多模态模型&#xff0c;能够支持语音、图像、编程代码和视频等多种格式&#xff0c;这标志着…

【Linux】多线程(线程概念+线程控制)

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

负载均衡下的webshell上传+nginx解析漏洞

负载均衡下的webshell上传 一&#xff0c;负载均衡下webshell上传的四大难点 难点一&#xff1a;需要在每一台节点的相同位置上传相同内容的webshell 我们需要在每一台节点的相同位置都上传相同内容的 WebShell一旦有一台机器上没有&#xff0c;那么在请求轮到这台机器上的时…

二分查找-迭代法

Go 算法 每天5道&#xff0c;开心快乐每一天 一点都不开心 哈哈哈哈哈哈 -2.1 day 1 1.22&#xff08;1.23 1.25 1.29&#xff09; 1.23 已复习 704. 二分查找 力扣题目链接 //左闭右开 func search(nums []int, target int) int { right : len(nums) left : 0; for le…