Drawable、Bitmap、Canvas、Paint和 Matrix 的使用(二)

本文详细解析了Android中Matrix类的set,pre,post方法调用顺序及其对平面进行缩放、平移、旋转及倾斜操作的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Matrix的set,pre,post调用顺序

Matrix主要用于对平面进行缩放,平移,旋转以及倾斜操作,为简化矩阵变换,Android封装了一系列方法来进行矩阵变换。
pre系列方法:preScale,preTranslate,preRotate,preSkew;
set系列方法:setScale,setTranslate,setRotate,setSkew;
post系列方法:postScale,postTranslate,postRotate,postSkew;

Matrix调用一系列set,pre,post方法时,可视为将这些方法插入到一个队列,按照队列中从头至尾的顺序调用执行。

其中pre表示在队头插入一个方法,post表示在队尾插入一个方法,而set表示把当前队列清空,并且总是位于队列的最中间位置。当执行了一次set后,pre方法总是插入到set前部的队列的最前面,post方法总是插入到set后部的队列的最后面。

Matrix m = new Matrix();
m.setRotate(45); 
m.setTranslate(80, 80);
只有m.setTranslate(80, 80)有效,因为m.setRotate(45)被清除;

Matrix m = new Matrix();
m.setTranslate(80, 80);
m.postRotate(45);
先执行m.setTranslate(80, 80),后执行m.postRotate(45);

Matrix m = new Matrix();
m.setTranslate(80, 80);
m.preRotate(45);
先执行m.preRotate(45),后执行m.setTranslate(80, 80);

Matrix m = new Matrix();
m.preScale(2f,2f);    
m.preTranslate(50f, 20f);   
m.postScale(0.2f, 0.5f);    
m.postTranslate(20f, 20f);  
执行顺序:m.preTranslate(50f, 20f)-->m.preScale(2f,2f)-->m.postScale(0.2f, 0.5f)-->m.postTranslate(20f, 20f)

Matrix m = new Matrix();
m.postTranslate(20, 20);   
m.preScale(0.2f, 0.5f);
m.setScale(0.8f, 0.8f);   
m.postScale(3f, 3f);
m.preTranslate(0.5f, 0.5f);
执行顺序:m.preTranslate(0.5f, 0.5f)-->m.setScale(0.8f, 0.8f)-->m.postScale(3f, 3f)
注意:m.setScale(0.8f, 0.8f)清除了前面的m.postTranslate(20, 20)和m.preScale(0.2f, 0.5f);  
<think>好的,我现在需要解决用户提供的Kotlin代码中rotateBitmap无法显示的问题。首先,我应该仔细阅读代码,理解每个步骤的作用,然后找出可能的问题所在。 用户代码的大致流程是:从资源中解码一个位图,显示在original视图上。然后创建一个Matrix,设置旋转90度。接着创建一个与原始位图相同宽高的rotateBitmap,并用Canvas绘制应用了matrix的原始位图。最后将rotateBitmap设置到rotate视图上,但发现不显示。 首先,我应该检查Matrix使用是否正确。用户调用了matrix.postRotate(90f),这里可能的问题在于旋转的中心点。默认情况下,旋转是围绕坐标原点(0,0)进行的,这可能导致图片旋转后超出画布范围,从而不可见。正确的做法可能是需要调整Matrix的旋转中心,或者调整画布的大小以适应旋转后的图像。 接下来,观察创建rotateBitmap的方式。用户使用Bitmap.createBitmap(bitmap.width, bitmap.height, bitmap.config)来创建新位图,但原始图片旋转90度后,宽度高度会互换。例如,原本宽为W,高为H的图片,旋转90度后应该变为高为W,宽为H。因此,创建新位图时如果保持原始尺寸,会导致图像被裁剪或者显示不全。所以正确的做法应该是将新位图的宽高设置为原始的高宽,即交换两者的值。 另一个可能性是Canvas绘制时的参数是否正确。用户调用canvas.drawBitmap(bitmap, matrix, null),这里是否正确应用了matrix?可能需要检查matrix是否正确配置。另外,Paint参数为null是否会有影响,不过通常可以为null。 另外,可能的问题还有是否位图被正确创建。需要确认Bitmap.createBitmap的参数是否正确,特别是宽高是否合理。例如,原图宽100,高200,旋转后新位图宽应为200,高100,但用户代码中仍然使用原宽高,导致新位图尺寸不足以容纳旋转后的图像,可能被裁剪,导致显示空白。 再考虑旋转后的绘制位置。如果旋转导致图像超出画布范围,即使正确旋转了,也可能在画布外,所以需要调整Matrix平移,或者使用合适的参数来确保绘制在正确的位置。例如,使用Matrix的postTranslate方法来调整位置。 总结可能的问题点: 1. rotateBitmap的宽高未交换,导致图像被裁剪。 2. Matrix旋转中心点问题,导致图像偏移出画布。 3. 绘制时未调整位置,导致图像在画布外。 解决方案步骤可能包括: - 交换rotateBitmap的宽高。 - 调整Matrix的旋转中心点为原始位图的中心,或调整绘制的位置。 - 使用Bitmap.createBitmap的正确尺寸,并正确应用Matrix。 例如,正确的方式应该是: val matrix = Matrix().apply { postRotate(90f, bitmap.width / 2f, bitmap.height / 2f) // 围绕中心旋转 } // 旋转后的宽高交换 val rotateBitmap = Bitmap.createBitmap(bitmap.height, bitmap.width, bitmap.config) // 或者使用更安全的方法,如: val rotatedWidth = bitmap.height val rotatedHeight = bitmap.width val rotateBitmap = Bitmap.createBitmap(rotatedWidth, rotatedHeight, bitmap.config) val canvas = Canvas(rotateBitmap) // 调整绘制的位置,可能需要在绘制时应用平移,或者Matrix已经处理了位置 或者,更简单的方法是使用Bitmap.createBitmap的另一个重载方法,直接应用Matrix并处理边缘情况: val matrix = Matrix().apply { postRotate(90f) } val rotateBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) 但需要注意,Bitmap.createBitmap的这个方法可能返回null,如果旋转或缩放导致无法创建位图,所以需要检查。但用户原来的代码中并没有使用这个方法,而是手动创建画布绘制,这可能存在问题。 因此,正确的做法应该是调整新位图的宽高,并确保Matrix正确应用了旋转平移,使得图像在画布内可见。例如,当旋转90度后,图像的位置可能需要平移,否则可能绘制到画布外。例如,旋转后原点(0,0)处的图像部分可能不在可视区域,需要平移使得整个图像可见。 因此,修改后的代码可能是: val matrix = Matrix().apply { postRotate(90f) postTranslate(bitmap.height.toFloat(), 0f) // 假设旋转后需要向右平移原图的高度,以显示在画布内 } 或者,更准确的方式是,计算旋转后的位置,确保图像在画布中央。或者,直接使用Bitmap.createBitmap的正确方法。 另外,可能用户将旋转后的位图尺寸保持原图相同,导致无法容纳旋转后的图像,从而被裁剪。例如,原图是横向的,旋转90度后变为竖向,但新位图还是横向的尺寸,导致图像被截断,显示不全,看起来空白。 所以,解决这个问题的关键在于正确设置新位图的尺寸为交换后的宽高,并调整Matrix的旋转中心或平移,使得图像正确绘制在新位图内。 因此,正确的代码应该如下: val matrix = Matrix().apply { // 设置旋转中心为原图的中心点 setRotate(90f, bitmap.width / 2f, bitmap.height / 2f) } // 旋转后的尺寸是原图的高宽 val rotateBitmap = Bitmap.createBitmap(bitmap.height, bitmap.width, bitmap.config) val canvas = Canvas(rotateBitmap) // 调整绘制的位置,可能需要平移 matrix.postTranslate(-bitmap.width / 2f + rotateBitmap.width / 2f, -bitmap.height / 2f + rotateBitmap.height / 2f) canvas.drawBitmap(bitmap, matrix, null) 或者更简单的方式是,使用正确的旋转方法。例如,在创建Matrix后,先旋转,然后根据旋转后的尺寸创建位图,并调整绘制的位置。 或者,直接使用Bitmap.createBitmap的另一个方法: val rotateBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) 但需要确保matrix正确,并且createBitmap的参数正确。 综上,用户的问题可能是因为rotateBitmap的尺寸没有调整,导致图像被裁剪,或者Matrix没有正确调整位置,导致绘制到画布外。解决方案是交换宽高,并调整Matrix平移。</think>让我们逐步分析并解决`rotateBitmap`无法显示的问题: --- ### **问题分析** 1. **尺寸错误** - 原图旋转90度后,**宽度高度会互换**。若保持`rotateBitmap`尺寸与原图相同,旋转后的图像会被裁剪。 - *示例*:原图尺寸为 $width \times height$,旋转后应为 $height \times width$。 2. **旋转中心偏移** - 默认旋转围绕坐标原点 $(0,0)$,可能导致图像绘制到画布外,无法显示。 --- ### **解决方案** #### **步骤1:调整旋转后的位图尺寸** 交换原图的宽高创建新位图: ```kotlin val rotateBitmap = Bitmap.createBitmap(bitmap.height, bitmap.width, bitmap.config) ``` #### **步骤2:修正旋转中心与平移** 通过`Matrix`调整旋转中心,并平移图像到画布内: ```kotlin val matrix = Matrix().apply { // 将旋转中心设为原图中心 postRotate(90f, bitmap.width / 2f, bitmap.height / 2f) // 平移图像到新位图中心 postTranslate( (rotateBitmap.width - bitmap.width) / 2f, (rotateBitmap.height - bitmap.height) / 2f ) } ``` #### **优化代码(完整版)** ```kotlin private fun initView() { val bitmap = BitmapFactory.decodeResource(resources, R.drawable.snipaste) binding.original.setImageBitmap(bitmap) // 创建Matrix并设置旋转(中心为原图中心) val matrix = Matrix().apply { postRotate(90f, bitmap.width / 2f, bitmap.height / 2f) } // 创建正确尺寸的旋转位图(交换宽高) val rotateBitmap = Bitmap.createBitmap( bitmap.height, bitmap.width, bitmap.config ) // 绘制到新位图 val canvas = Canvas(rotateBitmap) canvas.drawBitmap(bitmap, matrix, null) binding.rotate.setImageBitmap(rotateBitmap) } ``` --- ### **原理说明** - **尺寸调整**:旋转后图像的宽高互换,新位图需匹配新尺寸避免裁剪。 - **矩阵变换**: - `postRotate(angle, px, py)` 围绕原图中心旋转,避免偏移。 - 通过平移确保旋转后的图像位于新画布中央。 --- ### **其他注意事项** - **性能优化**:若处理大图,建议在子线程进行,避免主线程卡顿。 - **资源释放**:不再使用的`Bitmap`应及时调用`recycle()`。 通过以上调整,`rotateBitmap`应能正常显示旋转后的图像。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪舞飞影

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值