Android 设置头像 - 裁剪及圆形头像

    书接上文 Android 设置头像 - 相册拍照,通过相册和照片的设置就可以获取到需要的头像信息,但是在通常情况下,我们还想要实现针对头像的裁剪功能和圆形头像功能。

先上截图:
在这里插入图片描述

图像裁剪

    通常裁剪可以分为程序自动裁剪和用户选择裁剪两种方式,程序自动裁剪及程序中设置固定的裁剪比例然后系统自动进行裁剪,Glide即可实现该功能。但这种实现方式往往不能满足用户实际需求,及实际裁剪需要用户进行选择图片裁剪范围。下面将提供两种图片裁剪的实现逻辑,出了本文描述的裁剪实现逻辑外还有自定义裁剪view等其他实现逻辑,由于技术有限,再次仅仅阐述较为简单的两种实现逻辑。

第三方裁剪库

    目前存在很对开源的第三方Android裁剪工具库,通过比较uCrop的裁剪工具库较为流行,本文将以该裁剪工具集成为例进行说明。uCrop的GitHub地址点这里。通过README文档可知,集成该工具需要以下操作:

  • gradle引入
  • AndroidManifest.xml中声明Activity
  • 业务代码中调用UCrop进行裁剪
  • 通过onActivityResult接收裁剪结果intent

    上述四个过程在github中作者都进行了详细说明,下面进行我理解的简单说明:
采用该工具需要传入目标Uri
    使用该工具进行裁剪需要输入源Uri和目标Uri,及被参见图片Uri和裁剪后图片存放的Uri,不同Android版本的Uri获取方式不同,Uri相关内容本人也一知半解,后续了解后将另文说明。
AndroidManifest.xml中声明Activity
    相信使用module开发或者引入过arr资源包的都清楚需要在AndroidManifest.xml中引入第三方arr的Activity文件。根据这个说明不难推断出Ucrop为一个arr资源包并非jar包,并且结合网上了解到的自定义裁剪试图的实现逻辑不难推断出,Ucrop也实现了一个自定义Activity进行裁剪,当用户发起裁剪请求时,将跳转到Ucrop的Activity中,待裁剪完成后进行回跳并携带裁剪结果。

通过onActivityResult接收裁剪结果intent
    UCrop.start()方法将进行裁剪,通过查看源码,该方法调用了activity.startActivityForResult(getIntent(activity), requestCode);方法,因此需要重写onActivityResult方法进行接收回跳携带参数。但是由于startActivityForResult即将弃用,所以这种方式我不建议使用。考虑是否可以通过重写UCrop.start方法通过ActivityResultLauncher.launch的方法进行裁剪调用。

系统默认裁剪intent调用

    系统默认裁剪实现是裁剪过程中最简单的实现方式,按照百度结果只需要创建一个Intent intent = new Intent(“com.android.camera.action.CROP”);意图并进行相关参数配置即可。下面首先展示我的实现逻辑

  • 首先配置ActivityResultContract如下
/*** 裁剪照片的contract** @author baiyang* @since 2024-04-28*/
public class CropImageResultContract extends ActivityResultContract<Intent, Intent> {public static final String AUTHORITY = "com.ldr.imosApp.provider";public static final String IMAGE_TYPE = "image/jpeg";public static final String JPG_TYPE = "jpg";private String type;private Uri uri;@NonNull@Overridepublic Intent createIntent(@NonNull Context context, Intent input) {input.putExtra("crop", "true");input.putExtra("aspectX", 1);input.putExtra("aspectY", 1);input.putExtra("outputX", 256);input.putExtra("outputY", 256);input.putExtra("return-data", true);String mimeType = null;String fileName = null;mimeType = IMAGE_TYPE;fileName = System.currentTimeMillis() + "." + JPG_TYPE;Uri mediaUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {ContentValues values = new ContentValues();values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);uri = context.getContentResolver().insert(mediaUri, values);} else {uri = FileProvider.getUriForFile(context, AUTHORITY,new File(context.getExternalCacheDir().getAbsolutePath(), fileName));}input.putExtra(MediaStore.EXTRA_OUTPUT, uri);return input;}/*** 返回拍照结果,因为在调用相机的过程中设置了EXTRA_OUTPUT,因此返回时intent=null,需要重新设置一下** @param resultCode* @param intent* @return*/@Overridepublic Intent parseResult(int resultCode, @Nullable Intent intent) {if (resultCode != Activity.RESULT_OK) {return null;}intent = new Intent();intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);return intent;}
}

    上述代码在拍照图库文档中已经进行详细说明,在此需要补充一点疏漏是:我们在createIntent方法中创建了一个Uri,那么intent返回的时候通过getData就不能获取裁剪结果的Uri了,而且我们创建的这个Uri会导致裁剪后的图片将作为一个资源存放到了我们的通过中,这也是为什么在Android 设置头像 - 相册拍照一文从图库中选择照片的createIntent方法中我没有创建Uri的原因,如果创建了会导致图库中存在两张重复的图片。在上述代码实现初期,我并没有创建Uri,直接通过getData进行获取Uri,在模拟器上进行测试是可以通过的,但是使用真机测试的过程中依旧会出现裁剪正常进行,但是裁剪结果getData=null的情况。目前原因不详,怀疑可能是通过intent调用默认的裁剪实现后,裁剪的返回结果在不同机型上进行了不同方式的返回,因此通过创建Uri进行接收裁剪结果是最稳妥的实现方式

  • 进行裁剪结果回调函数实现
    /*** 裁剪照片的回调函数*/private final ActivityResultCallback<Intent> cropCallback = result -> {if (Objects.nonNull(result)) {Uri uri = result.getParcelableExtra(MediaStore.EXTRA_OUTPUT);Glide.with(PersonalInformationActivity.this).load(uri).into(binding.headSculpture);} else {LogUtils.e("裁剪照片回调失败,未回传相关数据");}};

即获取结果后直接通过Glide进行图片回显。后续的圆形图像可以通过Glide进行实现。

  • intent调用
        在进行intent调用之前首先需要获取ActivityResultLauncher,如下:
        cropResultLauncher = registerForActivityResult(new CropImageResultContract(),cropCallback);

    intent调用是需要进行裁剪,而裁剪过程应该是在选择图片或者拍照后进行,因此需要修改原拍照图库的回调函数进行调用裁剪的intent,代码如下:

    /*** 拍照或者选择图库照片后回调*/private final ActivityResultCallback<Intent> callback = result -> {if (Objects.nonNull(result)) {Uri uri = result.getParcelableExtra(MediaStore.EXTRA_OUTPUT);// 进行裁剪Intent intent = new Intent("com.android.camera.action.CROP");intent.setDataAndType(uri, "image/*");cropResultLauncher.launch(intent);
//            Glide.with(getApplicationContext()).load(uri).into(binding.headSculpture);} else {LogUtils.e("拍照、录像数据回调失败,未回传相关数据");}};

    上述及使用系统默认的裁剪工具进行裁剪的实现方式,不同手机,不同android版本的系统默认裁剪工具并不相同,因此最终实现效果也不相同,由于手头真机数量有限,并不能针对更多机型进行测试,所以并不确定上述逻辑实现可以适配所以手机,而且对于没有系统默认裁剪工具的机型,上述代码无法进行裁剪,而Ucrop工具可以实现裁剪。

intent到底是什么?

    Intent(意图)主要是解决Android应用的各项组件之间的通讯。
    Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给被调用的组件,并完成组件的调用。
    因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。

    上面为百度词条对其的解释,intent可以实现各个组件的通信。回忆我们实现的Activity跳转逻辑,通过startActivity(intent);方法进行跳转,intent我们一般进行下面定义:

Intent intent = new Intent();
intent.setClass(getApplicationContext(), MainActivity.class);

    上述代码表示从当前Activity跳转到MainActivity,可以看到我们并没有进行MainActivity初始化跳转等特殊设置,我没有深入研究Android底层源码,但是不难推测出当startActivity(intent);方法被调用后,intent意图交由Android底层进行处理,Android系统根据intent传参判断该意图需求,如果是Activity跳转,则从Activity注册表中获取目的Activity并进行生命周期的调用(个人揣测,不准欢迎斧正)。
    上面例子为Activity跳转,一般都是同一APP内部跳转,但是当我们进行拍照、调用通讯录等系统级别的操作时也是借助Intent进行实现的,那么可以大胆推测,intent的处理时交由Android底层进行处理,他并不是某个app内部进行处理的,当底层接收到一个访问相机的intent时,将判断是否具备访问权限,如果具备则调用相机。
    通过上述分析,我们可以继续推测调用系统裁剪及Intent intent = new Intent(“com.android.camera.action.CROP”);这个意图在交由Android底层进行处理的时候,Android底层将从它的Activity注册表中找到相关Activity进行跳转。在此引申下属代码:

        <activityandroid:name=".ui.GuideActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity>

    这段代码写Android的都清楚,Android首界面的设置,设置Android受界面需要声明intent-filter标签,并且需要设置android:exported=“true”,表明该Activity允许外部访问(及允许Android底层进行调用启动)。

圆形头像

    圆形头像的实现可记住Glide工具,按照如下代码:

            RequestOptions options = new RequestOptions().circleCropTransform();Glide.with(PersonalInformationActivity.this).load(uri).apply(options).into(binding.headSculpture);

    在进行into到目标view的过程中Glide使用了bitmapTransform进行转化,使用的是CropCircleTransformation实现,该实现类将图片转化为圆形图片。通过借助Glide的实现圆形头像较为简单,在此不再深入Gilde的具体细节。

总结

    通过裁剪和圆形头像的实现更加深入的对ActivityResultLauncher进行了学习,并在实现的过程中对Intent有了更加深入的思考,如果本文内容存在问题欢迎各位大佬进行斧正。总结本文内容。

  • Ucrop工具实现图片裁剪
  • Intent系统默认裁剪实现类
  • intent深入思考
  • Gilde圆形图片的实现

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

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

相关文章

基于SpringBoot实现各省距离Excel导出实战

目录 前言 一、列表及图表信息展示 1、数据过滤调整 2、信息列表及图表展示 3、Excel写入 二、界面可视化 1、Echarts图表和列表展示 2、城市详情和下载功能设计 三、成果展示 1、图表展示 2、部分城市数据分析 总结 前言 今天是五一黄金周假期第二天&#xff0c;不知…

电脑自带dll修复在哪里,使用dll修复工具解决dll问题

在我们日常与电脑相伴的工作与学习过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中最常见的就是“无法找到.dll”或“找不到.dll文件”。这种情况通常是由于dll文件丢失或损坏导致的。dll文件是动态链接库文件&#xff0c;它包含了许多程序运行所需的函数和资源…

使用 BurpSuite 基于 Token 机制实施暴力破解

前言 Token是一种用于身份验证和授权的令牌&#xff0c;通常由服务器生成并发送给客户端&#xff0c;客户端在后续的请求中携带该令牌来进行身份验证和授权操作。Token的使用可以增强应用程序的安全性&#xff0c;避免了直接传递敏感凭证&#xff08;如用户名和密码&#xff0…

Golang | Leetcode Golang题解之第61题旋转链表

题目&#xff1a; 题解&#xff1a; func rotateRight(head *ListNode, k int) *ListNode {if k 0 || head nil || head.Next nil {return head}n : 1iter : headfor iter.Next ! nil {iter iter.Nextn}add : n - k%nif add n {return head}iter.Next headfor add > …

golang判断通道chan是否关闭的2种方式

chan通道在go语言的办法编程中使用频繁&#xff0c;我们可以通过以下2种方式来判断channel通道是否已经关闭&#xff0c;1是使用 for range循环&#xff0c;另外是通过 for循环中if 简短语句的 逗号 ok 模式来判断。 示例代码如下&#xff1a; //方式1 通过for range形式判断…

进销存单机版和excel进销存那个好用

进销存单机版和EXCEL进销存哪个好用&#xff1f;单机版是安装在单台电脑上使用的&#xff0c;它不能像网络版一样可以多台电脑同时共享数据&#xff0c;所以进销存单机版有一个优势就是不需要连接网络也可以使用。 进销存单机版 进销存软件单机版是经过开发人员设计好的一种信…

es环境安装及php对接使用

Elasticsearch Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口。Elasticsearch是用Java语言开发的&#xff0c;并作为Apache许可条款下的开放源码发布&#xff0c;是一种流行的…

postman一直转圈圈,无法启动

解决 地址栏输入%appdata%进入此目录&#xff0c;删除%appdata%目录下的postman文件可以解决问题。

贪心算法 Greedy Algorithm

1) 贪心例子 称之为贪心算法或贪婪算法&#xff0c;核心思想是 将寻找最优解的问题分为若干个步骤 每一步骤都采用贪心原则&#xff0c;选取当前最优解 因为没有考虑所有可能&#xff0c;局部最优的堆叠不一定让最终解最优 v2已经不会更新v3因为v3更新过了 贪心算法是一种在…

Ps 滤镜:智能锐化

Ps菜单&#xff1a;滤镜/锐化/智能锐化 Filter/Sharpen/Smart Sharpen 智能锐化 Smart Sharpen滤镜可以用来提高图像的视觉清晰度和边缘细节&#xff0c;同时最大限度地减少常见的锐化问题如噪点和光晕等。 “智能锐化”滤镜通过自适应算法分析图像内容&#xff0c;针对不同的细…

省级财政收入、支出、第一、二、三产业增加值、工业增加值、金融业增加值占GDP比重数据(1978-2022年)

01、数据介绍 财政收支作为国家治理的基础&#xff0c;越来越受到社会各界的关注。同时&#xff0c;产业结构的优化与升级也是中国经济持续增长的关键因素。本数据对中国省级财政收入、支出占GDP的比重以及第一、二、三产业的增加值占GDP的比重和工业增加值占GDP的比重、金融业…

Pandas入门篇(二)-------Dataframe篇5(进阶)(Dataframe的时间序列Dataframe最终篇!!)(机器学习前置技术栈)

目录 概述一、pandas的日期类型&#xff08;一&#xff09;datetime64类型的特点&#xff08;二&#xff09; 时间序列的创建1.从字符串创建datetime64类型2. 整数&#xff08;Unix时间戳&#xff09;创建datetime64类型3.导入数据时直接转换 &#xff08;三&#xff09;dateti…

打印机-STM32版本 硬件部分

最终PCB EDA工程: 一、确定芯片型号 根据项目需求&#xff0c;梳理需要用到的功能&#xff0c; 电量检测&#xff1a;ADC 按键&#xff1a;IO input外部中断 LED&#xff1a;IO output 温度检测&#xff1a;ADC 电机控制&#xff1a;IO output 打印通讯&#xff1a;SPI …

C++string类使用大全

目录 温馨提示&#xff1a;这篇文章有约两万字 什么是string类&#xff1f; 一. 定义和初始化string对象 1.string的构造函数的形式&#xff1a; 2.拷贝赋值运算符 3.assign函数 二.string对象上的操作 1.读写string对象 2.读取未知数量的string对象 3.使用getline …

windows ubuntu sed,awk,grep篇:10.awk 变量的操作符

目录 62. 变量 64. 算术操作符 65. 字符串操作符 66. 赋值操作符 67. 比较操作符 68. 正则表达式操作符 62. 变量 Awk 变量以字母开头&#xff0c;后续字符可以是数字、字母、或下划线。关键字不能用作 awk 变量。 不像其他编程语言&#xff0c; awk 变量可以直接使…

实习面试之算法准备:数学题

目录 1 技巧2 例题2.1 Nim 游戏2.2 石子游戏2.3 灯泡开关 1 技巧 稍加思考&#xff0c;找到规律 2 例题 2.1 Nim 游戏 你和你的朋友&#xff0c;两个人一起玩 Nim 游戏&#xff1a; 桌子上有一堆石头。 你们轮流进行自己的回合&#xff0c; 你作为先手 。 每一回合&#xf…

SpringBoot 打包所有依赖

SpringBoot 项目打包的时候可以通过插件 spring-boot-maven-plugin 来 repackage 项目&#xff0c;使得打的包中包含所有依赖&#xff0c;可以直接运行。例如&#xff1a; <plugins><plugin><groupId>org.springframework.boot</groupId><artifact…

2024五一杯数学建模B题思路代码文章教学-交通需求规划与可达率问题

交通需求规划与可达率问题 问题总结&#xff1a; 问题一&#xff1a;在一个小型交通网络中&#xff0c;给定的起点和终点之间的交通需求需分配到相应路径上。目标是最大化任意一条路段出现突发状况时的交通需求期望可达率。 问题二&#xff1a;在一个较大的交通网络中&#xff…

负债56亿,购买理财产品遭违约,操纵虚假粉丝,流量在下滑,客户数量减少,汽车之家面临大量风险(三)

本文由猛兽财经历时5个多月完成。猛兽财经将通过以下二十二个章节、8万字以上的内容来全面、深度的分析汽车之家这家公司。 由于篇幅限制&#xff0c;全文分为&#xff08;一&#xff09;到&#xff08;十&#xff09;篇发布。 本文为全文的第七章、第八章、第九章。 目录 …

【Linux—进程间通信】共享内存的原理、创建及使用

什么是共享内存 共享内存是一种计算机编程中的技术&#xff0c;它允许多个进程访问同一块内存区域&#xff0c;以此作为进程间通信&#xff08;IPC, Inter-Process Communication&#xff09;的一种方式。这种方式相对于管道、套接字等通信手段&#xff0c;具有更高的效率&…