千家信息网

如何在Android中使用PhotoView实现头像/圆形裁剪控件

发表于:2025-11-11 作者:千家信息网编辑
千家信息网最后更新 2025年11月11日,这篇文章主要介绍"如何在Android中使用PhotoView实现头像/圆形裁剪控件"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"如何在Android中使用P
千家信息网最后更新 2025年11月11日如何在Android中使用PhotoView实现头像/圆形裁剪控件

这篇文章主要介绍"如何在Android中使用PhotoView实现头像/圆形裁剪控件"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"如何在Android中使用PhotoView实现头像/圆形裁剪控件"文章能帮助大家解决问题。

代码如下:

public class CircleCropView extends View { public final int CIRCLE_MARGIN = 50; public CircleCropView(Context context) { super(context); } public CircleCropView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public CircleCropView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public CircleCropView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, widthMeasureSpec); } @RequiresApi(api = Build.VERSION_CODES.O) @Override protected void onDraw(Canvas canvas) { canvas.save(); Path path = new Path(); Rect viewDrawingRect = new Rect(); getDrawingRect(viewDrawingRect); float radius = viewDrawingRect.width() / 2 - CIRCLE_MARGIN; path.addCircle(viewDrawingRect.left + radius + CIRCLE_MARGIN, viewDrawingRect.top + radius + CIRCLE_MARGIN, radius, Path.Direction.CW); Paint outsidePaint = new Paint(); outsidePaint.setAntiAlias(true); outsidePaint.setARGB(151, 0, 0, 0); canvas.clipPath(path, Region.Op.DIFFERENCE); canvas.drawRect(viewDrawingRect, outsidePaint); canvas.restore(); }}

SquarePhotoView只是在PhotoView的基础上改了长宽,重写一下onMeasure方法即可:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, widthMeasureSpec); }

那么现在最关键的一步,就是从PhotoView获取当前图片显示区域的Drawable或Bitmap了。粗略看了一下PhotoView的函数,并没有找到能用的(囧)。解决第一个坑的笨办法就是,自己动手丰衣足食--直接拿原图的bitmap,然后问PhotoView要当前图片的变形矩阵,自个儿通过矩阵一步步变形拿到对应的位图。

思路其实是没问题的,然而第二个坑又出现了(囧)。这里的变形矩阵,我最早百度的结果是getSuppMatrix,源码我没有细看,但掉坑的过程中据我观察,猜测应该是对应最新一次的手势变形结果(不确定= =,也可能是其他坑综合导致的错误结果)。总之最后我查了一会源码,最终确定用的是getDisplayMatrix。

紧接着是第三个坑,坑多了就习惯了。矩阵中的XY位移量,我起初以为是显示区域中心相对于原图中心的位移,即如果仅有缩放操作的话,位移应该为0。但实际通过特殊位置(例如取四个顶点)的裁剪结果来看,这里的XY位移量实际最后显示区域左上角的点相对原点(即原图左上角)的位移,简单点说,可以把位移量作为最终显示区域左上角的坐标。

然后我就迎来了第四个坑(?)。这个坑现在回头看其实是很简单不应该栽进去的,然而当时还没想通的时候确实很慌(唉)。这个坑的问题就出在,Matrix里的值是基于手势的,也就是说,是基于屏幕像素(换句话说,是基于实际显示的图片)的。而对位图进行裁剪时,是基于原图像素的。那么这里还存在一个为了正常显示而导致的缩放比例的问题,例如原图是3000x4000,由于屏幕分辨率是1080*1920,那么实际显示时,图片是缩小了的,这个比例是9/25。所以在裁剪的过程中,需要把位移量再放大25/9倍进行还原。

下面是裁剪部分的关键代码(最后偷了一下懒,没有裁圆形,只是用CIrcleImageView显示):

fun cropImage(){ var degree = ImageUtils.readPictureDegree(imagePath) var bitmap = ImageUtils.getRotatedBitmap(BitmapFactory.decodeFile(imagePath),degree) var width: Int = 0 var startX: Int = 0 var startY: Int = 0 if (bitmap.width < bitmap.height){ startY = (bitmap.height - bitmap.width) / 2 width = bitmap.width }else{ startX = (bitmap.width - bitmap.height) / 2 width = bitmap.height } var matrix = Matrix() photo_preview.getDisplayMatrix(matrix)//获取变形矩阵,直接取scaleX或translationX没用 var values = FloatArray(9, {0.0f}) matrix.getValues(values) var expWidth = Math.round(bitmap.width * values[0])//缩放x var expHeight = Math.round(bitmap.height * values[4])//缩放y  var bitmap1 = Bitmap.createScaledBitmap(bitmap, expWidth, expHeight, false) val ratio = width * 1.0f / photo_preview.width startX = Math.round(startX * values[0] - values[2] * ratio) startY = Math.round(startY * values[4] - values[5] * ratio) var bitmap2 = Bitmap.createBitmap(bitmap1, startX, startY, width, width, null, false) saveImage(bitmap2) }

这里还有几个小坑需要解释一下:

读取bitmap时需要注意一下角度。这个是我在裁剪本地图片和网络图片的时候发现的,有些是正的有些就是转了90度。每个手机也不一定一样,所以保险起见,需要从图片的EXIF信息里面获取需要旋转的角度,然后再进一步处理。
我这里因为最终显示的是正方形,而且选的scaleType是centerCrop。所以默认就是显示中间的那一块。所以裁减时的原点也需要从正方形的左上角开始。这里是计算两种情况下的原点坐标:

var startX: Int = 0 var startY: Int = 0 if (bitmap.width < bitmap.height){ startY = (bitmap.height - bitmap.width) / 2 width = bitmap.width }else{ startX = (bitmap.width - bitmap.height) / 2 width = bitmap.height }

关于"如何在Android中使用PhotoView实现头像/圆形裁剪控件"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注行业资讯频道,小编每天都会为大家更新不同的知识点。

图片 原图 实际 矩阵 圆形 区域 左上角 结果 问题 头像 控件 原点 就是 知识 过程 代码 像素 关键 只是 坐标 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 我们服务器立足北美 互联网对科技发展有什么好处 组态王打包后不能联数据库 西电网络安全学院复试题 服务器安全证书不被信任怎么设置 普联摄像头服务器地址是哪里 hp服务器远程管理许可 如何查看当前数据库所以表 浦东新区二手网络技术施工 西安手机软件开发哪家公司好 互联网教父未来金融科技 赴欧洲搞软件开发工作 数据库表和视图怎么找 网络安全教育缘由 接入网网络技术短视频 低代码软件开发工具 计算机网络技术就业的前景 不同数据库双写 楼宇软件开发是什么意思 软件开发办公空间 数据库的数据怎么样打印条码 枣庄网络安全性 火影忍者怎么看好友在哪个服务器 数据库怎么查相同的订单 伴飞网络技术 辽宁新一代软件开发价格优惠 大学能学会软件开发吗 武汉宇轩网络技术有限公司 华为服务器做系统摁哪个键 敏哥化身服务器管理女神
0