千家信息网

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

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要介绍"如何在Android中使用PhotoView实现头像/圆形裁剪控件"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"如何在Android中使用P
千家信息网最后更新 2026年11月03日如何在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安全错误 数据库的锁怎样保障安全 伟宏互联网科技 广州万易互联网科技有限公司 互联网科技公司华为 网络科技有限互联网 世界互联网领先科技成果 极限挑战互联网科技 时间互联网络科技 广州善班互联网科技 互联网对科技的发展 苏州五指互联网络科技有限 晓花互联网科技有限公司网址 江阴互联网智能科技产品进口 企晟互联网信息科技有限公司 用友工业互联网科技发展 上海钢联属于互联网科技股吗 城市宝互联网科技有限公司 扫呗互联网科技有限公司 新氧科技和美国互联网有关系吗 济南小医互联网科技有限公司招聘 互联网高科技行业有哪些企业 广州紫鲸互联网科技有限公司 互联网和科技创新 互联网科技股票 奇士达互联网科技 无线互联网科技 居家互联网科技有限公司 互联网科技股午盘股票涨跌 阿里巴巴算科技企业还是互联网 唯美互联网科技 玉溪新华互联网科技怎么选
0