一、为什么你的图片需要“转”起来?
想象一下:用户上传了一张歪脖子的自拍,你的APP如果能自动摆正,瞬间逼格飙升!旋转图像不仅是修图基本功,更是人脸识别、AR导航、游戏引擎等场景的刚需。比如:
- 照片编辑器:支持手动旋转校正角度
- 游戏技能特效:剑气波动伴随图片旋转
- 动态壁纸:云朵随风向缓慢转动
但很多新手容易翻车:
// 错误示范:直接操作Bitmap导致内存泄漏
imageView.setRotation(90); // 表面旋转,保存图片时原样不变!
真相:setRotation()只是UI视觉效果,真正处理图像数据必须动用底层图形API!
二、旋转背后的数学魔法:矩阵才是真大佬
旋转的本质是坐标变换,而Android用Matrix类封装了这套数学操作:
// 旋转矩阵公式(绕原点(0,0))
新x = 原x * cosθ - 原y * sinθ
新y = 原x * sinθ + 原y * cosθ
但注意!手机屏幕的坐标系原点在左上角,直接套公式会翻车!解决方案:
- 平移大法:先把图像中心点移到原点
- 旋转操作:执行旋转计算
- 归位操作:把原点移回屏幕中心
Matrix matrix = new Matrix();
matrix.postTranslate(-width/2, -height/2); // 步骤1
matrix.postRotate(45); // 步骤2
matrix.postTranslate(newWidth/2, newHeight/2); // 步骤3
通俗理解:就像把饺子皮中心戳在手指上转圈,转完再放回案板!
三、手把手实战:四步旋转一张图
步骤1:创建原始Bitmap的副本
直接旋转原图可能导致数据污染,务必“抄作业”:
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
Bitmap targetBitmap = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);
步骤2:构建旋转矩阵
设置旋转角度和锚点(通常选图片中心):
Matrix matrix = new Matrix();
matrix.postRotate(45, targetBitmap.getWidth()/2, targetBitmap.getHeight()/2);
步骤3:生成新Bitmap
注意!旋转后图片尺寸可能变化,要用createBitmap指定新尺寸:
Bitmap rotatedBitmap = Bitmap.createBitmap(
targetBitmap,
0, 0,
targetBitmap.getWidth(),
targetBitmap.getHeight(),
matrix,
true
);
步骤4:显示并回收资源
imageView.setImageBitmap(rotatedBitmap);
// 重要!回收临时Bitmap防止内存泄漏
if (targetBitmap != srcBitmap) {
targetBitmap.recycle();
}
四、高能进阶:动态旋转动画
想要图片持续旋转?ValueAnimator+Matrix双剑合璧:
ValueAnimator animator = ValueAnimator.ofFloat(0, 360);
animator.setDuration(2000);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addUpdateListener(animation -> {
float angle = (float) animation.getAnimatedValue();
Matrix dynamicMatrix = new Matrix();
dynamicMatrix.postRotate(angle, bitmap.getWidth()/2, bitmap.getHeight()/2);
Bitmap frame = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), dynamicMatrix, true);
imageView.setImageBitmap(frame);
});
animator.start();
性能优化:频繁创建Bitmap会触发GC,建议用ImageView.setRotation()实现简单动画,复杂场景用OpenGL ES。
五、避坑指南:血泪总结的常见问题
- 黑边问题:旋转后角落出现黑色填充
Bitmap bgBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bgBitmap);
canvas.drawColor(Color.TRANSPARENT);
-
- 方案:创建足够大的画布,背景设为透明
- 尺寸计算错误:旋转后图片被裁剪
double rad = Math.toRadians(angle);
int newWidth = (int) (w * Math.abs(Math.cos(rad)) + h * Math.abs(Math.sin(rad)));
int newHeight = (int) (h * Math.abs(Math.cos(rad)) + w * Math.abs(Math.sin(rad)));
-
- 正确计算新画布尺寸:
- 内存溢出:大图旋转时APP崩溃
options.inSampleSize = 4; // 原图1/4尺寸加载
-
- 采用
BitmapFactory.Options采样压缩:
- 采用
六、完整示例:带进度回调的旋转工具类
public class ImageRotator {
public interface RotationListener {
void onRotateProgress(Bitmap bitmap);
void onRotateFinish(Bitmap result);
}
public static void rotateImage(final Bitmap src, final float angle,
final RotationListener listener) {
new AsyncTask<Void, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(Void... params) {
Matrix matrix = new Matrix();
matrix.postRotate(angle, src.getWidth()/2, src.getHeight()/2);
// 模拟进度回调
if (listener != null) {
handler.post(() -> listener.onRotateProgress(src));
}
return Bitmap.createBitmap(src, 0, 0,
src.getWidth(), src.getHeight(), matrix, true);
}
@Override
protected void onPostExecute(Bitmap result) {
if (listener != null) listener.onRotateFinish(result);
}
}.execute();
}
}
调用示例:
ImageRotator.rotateImage(originalBitmap, 45, new ImageRotator.RotationListener() {
@Override
public void onRotateProgress(Bitmap bitmap) {
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void onRotateFinish(Bitmap result) {
imageView.setImageBitmap(result);
progressBar.setVisibility(View.GONE);
}
});
七、结语:旋转不仅是技术,更是艺术
掌握了图像旋转,你的APP就拥有了“摆正世界”的能力!接下来可以挑战:
- 3D旋转:用
Camera.rotateY()实现翻页效果 - 多重特效:旋转+缩放+透明度复合动画
- GPU加速:通过
RenderScript提升大图处理速度
记住:好的特效应该像暗恋——用户感觉到了,但说不清哪里变了。现在就去让你的图片“旋”起来吧!
(全文约1680字,实操代码约占总篇幅40%)
Android图像旋转全解析

被折叠的 条评论
为什么被折叠?



