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.mzph.cn/news/621129.shtml

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

相关文章

【Python学习】Python学习17- File(文件) 方法

目录 [TOC](【Python学习】Python学习17- File(文件) 方法) 文章所属专区 Python学习 前言 本章节主要说明Python文件操作的具体说明 open()方法 Python open() 方法用于打开一个文件&#xff0c;并返回文件对象&#xff0c;在对文件进行处理过程都需要使用到这个函数&#…

Spark算子(RDD)超细致讲解

SPARK算子&#xff08;RDD&#xff09;超细致讲解 map,flatmap,sortBykey, reduceBykey,groupBykey,Mapvalues,filter,distinct,sortBy,groupBy共10个转换算子 &#xff08;一&#xff09;转换算子 1、map from pyspark import SparkContext# 创建SparkContext对象 sc Spark…

信息系统中的需求分析

软件需求是指用户对新系统在功能、行为、性能、设计约束等方面的期望。根据IEEE的软件工程标准词汇表&#xff0c;软件需求是指用户解决问题或达到目标所需的条件或能力&#xff0c;是系统或系统部件要满足合同、标准、规范或其他正式规定文档所需具有的条件或能力&#xff0c;…

Fastjson库将JSONObject转换为实体类

嗨&#xff0c;大家好&#xff0c;欢迎来到程序猿漠然公众号&#xff0c;我是漠然。 在Java编程中&#xff0c;使用Fastjson库将JSONObject转换为实体类的过程是一种常见的数据处理操作。Fastjson是一个由阿里巴巴开发的高性能JSON处理库&#xff0c;它简化了JSON数据的读写操作…

传感数据分析——傅里叶滤波:理论与公式

传感数据分析——傅里叶滤波&#xff1a;理论与公式 引言 在传感数据分析领域&#xff0c;傅里叶滤波是一种重要的信号处理技术&#xff0c;被广泛应用于各种领域&#xff0c;如通信、图像处理、音频处理以及生物医学等。本文将简单探讨傅里叶滤波的理论基础和相关公式&#…

Azure Machine Learning - 视频AI技术

Azure AI 视频索引器是构建在 Azure 媒体服务和 Azure AI 服务&#xff08;如人脸检测、翻译器、Azure AI 视觉和语音&#xff09;基础之上的一个云应用程序&#xff0c;是 Azure AI 服务的一部分。 有了 Azure 视频索引器&#xff0c;就可以使用 Azure AI 视频索引器视频和音频…

向伟人学习反焦虑,在逆境中崛起

第一、乐观的精神。 伟人在长期以来的读书、思考和实践&#xff0c;突破了思想认知限制&#xff0c;并最终在更高的思维层面上&#xff0c;建立起了强大的精神信念感。 在危险环境中表示绝望的人&#xff0c; 在黑暗中看不见光明的人&#xff0c; 只是懦夫与机会主义者。 —— …

蓝桥杯练习题(八)

&#x1f4d1;前言 本文主要是【算法】——蓝桥杯练习题&#xff08;八&#xff09;的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 …

[晓理紫]每日论文推送(有中文摘要,源码或项目地址)--机器人、视觉相关

专属领域论文订阅 VX关注{晓理紫}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 二维码 分类: 大语言模型LLM视觉模型VLM扩散模型视觉导航具身智能&#xff0c;机器人强化学习开放词汇&#xff0c;检测分割 晓理紫今日论…

二叉树的中序遍历【二叉树】【递归】

Problem: 94. 二叉树的中序遍历 文章目录 思路 & 解题方法复杂度Code 思路 & 解题方法 二叉树简单递归。 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) Code # Definition for a binary tree node. # class TreeNode: # def __init__(se…

Java重修第五天—面向对象3

通过学习本篇文章可以掌握如下知识 1、多态&#xff1b; 2、抽象类&#xff1b; 3、接口。 之前已经学过了继承&#xff0c;static等基础知识&#xff0c;这篇文章我们就开始深入了解面向对象多态、抽象类和接口的学习。 多态 多态是在继承/实现情况下的一种现象&#xf…

【汇编要笑着学】汇编模块化编程 | call和ret调用指令 | jmp跳转指令 | inc自加指令

Ⅰ.汇编模块化编程 0x00 一个简单的例子 我们了解模块化编程前先给出一个例子&#xff0c;方便大家快速了解。 SECTION MBR vstart0x7c00 ; 起始地址编译在0x7c00mov ax,cs mov ds,ax mov es,axmov ss,axmov fs,axmov sp,0x7c00 ; 上面这些都没什…

【工作日语】二、IT用语

バグ 缺陷ボタン 按钮チックする 检查クリアする 清除クリックする 点击クライアント 客户机コーディング 编码コマンド 命令コメント 注释コンパイルする 编译コンピュータ 计算机コントロール 控制カーソル 光标データ 数据データベース 数据库デバッグ 调试ドキュメント 文…

camtasia studio2024免费版如何下载?怎么录屏?

camtasia studio怎么录屏&#xff1f;Camtasia Studio是一款专门录制屏幕动作的工具&#xff0c;它能在任何颜色模式下轻松地记录屏幕动作&#xff0c;包括影像、音效、鼠标移动轨迹、解说声音等等。一般情况下&#xff0c;用户使用camtasia studio进行录屏时&#xff0c;需要注…

【进程调度】基于优先级的轮转调度C++实现算法

一、简介 1.1 背景 在计算机科学领域&#xff0c;进程调度是操作系统中一个关键的组成部分&#xff0c;它负责协调系统中各个进程的执行顺序&#xff0c;以最大程度地提高系统资源利用率。在这篇博客中&#xff0c;将深入探讨基于优先级的轮转调度算法&#xff0c;该算法结合…

Vue3-customRef的使用

读取数据前&#xff0c;需要先track&#xff08;&#xff09; 告诉Vue数据msg很重要&#xff0c;你要对msg进行持续关注&#xff0c;一旦msg变化就去更新 修改数据后&#xff0c;需要trigger&#xff08;&#xff09;收尾 通知Vue一下数据msg变化了 自定义ref如何防抖 hooks中…

UniApp调试支付宝沙箱(安卓)

先看下这里完整的交互的图&#xff1a;小程序文档 - 支付宝文档中心 一、打包 不管怎样&#xff0c;先打个包先。可以直接使用云端证书、云端打包&#xff0c;只需要指定包名即可。 二、在支付宝开放平台创建应用 这个参考官方的过程就可以了&#xff0c;只要有刚才打的包&…

Fastadmin上传图片服务端压缩图片,实测13.45M压缩为29.91K

先前条件&#xff1a;第一步安装compose&#xff0c;已安装忽略。 先上截图看效果 一、在fastadmin的根目录里面输入命令安装think-image composer require topthink/think-image二、找到公共上传类&#xff0c;application/common/library/Upload.php&#xff0c;在最下面…

Redis系列之使用Lua脚本

什么是lua脚本&#xff1f; lua语言是一个轻量级的脚本语言&#xff0c;可以嵌入其他语言中使用&#xff0c;调用宿主语言的功能。lua语法简单&#xff0c;小巧&#xff0c;源码一共才200多K&#xff0c;本身不会有太强的功能&#xff0c;很多的语言也支持lua语言&#xff0c;…

TensorRT(C++)基础代码解析

TensorRT(C)基础代码解析 文章目录 TensorRT(C)基础代码解析前言一、TensorRT工作流程二、C API2.1 构建阶段2.1.1 创建builder2.1.2 创建网络定义2.1.3 定义网络结构2.1.4 定义网络输入输出2.1.5 配置参数2.1.6 生成Engine2.1.7 保存为模型文件2.1.8 释放资源 2.2 运行期2.2.1…