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…

SPRINGBOOT+VUE项目实战

第一章> 1、ElementUI 2、布局与主体 3、增删改查 4、路由 5、播放组件 第二章> 6、分页 7、代码生成 8、导入导出 9、用户登录 10、…

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 > …

leaflet加载wms服务实现wms交互

leaflet地图与wms服务的交互&#xff0c;点击wms服务获取地理区域信息以及后续操作 加载wms服务 给地图添加监听点击事件 构造GetFeatureInfo发送请求&#xff0c;需要包含WMS服务的URL、请求的类型&#xff08;GetFeatureInfo&#xff09;、返回信息的格式&#xff08;通常是…

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更新过了 贪心算法是一种在…

react路由路径兼容.html

react路由路径兼容.html 背景根文件代码路由代码nginx配置 背景 因为react-router 的路径是没有.html后缀的&#xff0c;这样对于和其他系统有交互的时候&#xff0c;让别人改url地址不是很方便&#xff0c;所以想办法进行了老系统的兼容操作。 根文件代码 import React fro…

Spring Boot系列之条件注解

概述 想要搞懂Spring Boot自动配置&#xff0c;绕不过条件注解&#xff0c;即Conditional&#xff0c;可用于根据某个特定的条件来判断是否需要创建某个特定的Bean。本文分析基于spring-boot-autoconfigure-3.2.4版本。 Conditional注解可以添加在被Configuration、Component…

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…

力扣经典150题第四十九题:插入区间

目录 题目描述和要求示例解释解题思路算法实现复杂度分析测试和验证总结和拓展参考资料 题目描述和要求 给定一个无重叠的、按照区间起始端点排序的区间列表 intervals&#xff0c;其中 intervals[i] [starti, endi] 表示第 i 个区间的开始和结束。同样给定一个区间 newInter…

开源库交叉编译(七)--- FAAD2

官网&#xff1a;https://www.linuxfromscratch.org/blfs/view/svn/multimedia/faad2.html 源码&#xff1a;faad2-2.10.1.tar.gz Step 1&#xff1a;解压 tar -xvzf faad2-2.10.1.tar.gzcd faad2-2.10.1/ Step 2&#xff1a;创建安装目录 mkdir arm_faad2 Step 3&#…

MyBatis:mybatis入门

MyBatis 持久层框架,用于简化JDBC开发,是对原始JDBC程序的封装 持久层 数据访问层(dao),用来操作数据库 框架 一个半成品软件,一套可重用的通用软件代码模型. JDBC (Java DataBase Connectivity) 使用java语言操作关系型数据库的一套API 本质是sun公司官方定义的一套操…

打印机-STM32版本 硬件部分

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