如何围绕特定旋转点旋转Drawable,按指定角度且保持原位置?
嘿,这个需求我刚好做过,给你整理了完整的实现方案(以Android平台为例),分两种常见场景来写,还有旋转点的详细说明,你直接参考就行:
实现方案
场景1:自定义View中绘制并旋转Drawable
如果是在自定义View里绘制黑色矩形Drawable,想要围绕指定点旋转且保持原位置,核心是利用Canvas的旋转能力,配合画布状态的保存与恢复,步骤很清晰:
- 先获取Drawable的边界,把相对旋转点转换成View坐标系里的绝对位置
- 保存画布当前状态,避免旋转影响其他绘制内容
- 调用画布旋转方法,围绕指定点旋转
- 绘制旋转后的Drawable,此时它的原位置不会偏移
- 恢复画布状态,确保后续绘制不受干扰
具体代码示例:
public class RotatableRectView extends View { private Drawable blackRectDrawable; private float rotateAngle = 0f; // 旋转点:相对于Drawable自身的坐标(默认设为中心) private float pivotXInDrawable = 0f; private float pivotYInDrawable = 0f; public RotatableRectView(Context context) { super(context); init(); } public RotatableRectView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } private void init() { // 初始化黑色矩形Drawable blackRectDrawable = getResources().getDrawable(R.drawable.black_rect, null); // 设置Drawable初始位置(比如居中显示) int drawableWidth = blackRectDrawable.getIntrinsicWidth(); int drawableHeight = blackRectDrawable.getIntrinsicHeight(); int left = (getWidth() - drawableWidth) / 2; int top = (getHeight() - drawableHeight) / 2; blackRectDrawable.setBounds(left, top, left + drawableWidth, top + drawableHeight); // 默认旋转点为Drawable中心 pivotXInDrawable = drawableWidth / 2f; pivotYInDrawable = drawableHeight / 2f; } // 更新旋转角度的方法(用户输入角度后调用) public void setRotateAngle(float angle) { this.rotateAngle = angle; invalidate(); } // 设置自定义旋转点(相对于Drawable自身的坐标) public void setPivotInDrawable(float x, float y) { this.pivotXInDrawable = x; this.pivotYInDrawable = y; invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (blackRectDrawable == null) return; Rect bounds = blackRectDrawable.getBounds(); // 计算旋转点在View坐标系中的绝对位置 float absolutePivotX = bounds.left + pivotXInDrawable; float absolutePivotY = bounds.top + pivotYInDrawable; // 保存画布状态 canvas.save(); // 围绕指定点旋转画布 canvas.rotate(rotateAngle, absolutePivotX, absolutePivotY); // 绘制旋转后的Drawable blackRectDrawable.draw(canvas); // 恢复画布状态 canvas.restore(); } }
场景2:使用ImageView实现旋转
如果是用ImageView展示这个Drawable,通过Matrix控制旋转会更便捷,同样能保证原位置不变:
// 初始化ImageView和Drawable ImageView imageView = findViewById(R.id.image_view); Drawable blackRectDrawable = getResources().getDrawable(R.drawable.black_rect, null); imageView.setImageDrawable(blackRectDrawable); // 必须设置ScaleType为MATRIX,否则矩阵操作不生效 imageView.setScaleType(ImageView.ScaleType.MATRIX); // 用户输入角度后,调用此方法执行旋转 public void rotateDrawable(float inputAngle) { Matrix matrix = new Matrix(); Drawable drawable = imageView.getDrawable(); if (drawable == null) return; int drawableWidth = drawable.getIntrinsicWidth(); int drawableHeight = drawable.getIntrinsicHeight(); // 这里设置旋转点为Drawable中心,你可以换成自定义的x,y(范围0到Drawable宽/高) float pivotX = drawableWidth / 2f; float pivotY = drawableHeight / 2f; // 重置矩阵,添加旋转操作 matrix.reset(); matrix.postRotate(inputAngle, pivotX, pivotY); // 应用矩阵到ImageView imageView.setImageMatrix(matrix); }
旋转点说明
旋转点是Drawable自身坐标系内的一个坐标点,旋转操作会以这个点为轴心进行:
- 若旋转点为
(0,0):对应Drawable的左上角,旋转时左上角位置固定,其余部分绕它转动,整体视觉位置会偏移(除非旋转角度是360°的倍数)- 若旋转点为
(Drawable宽度/2, Drawable高度/2):对应Drawable的中心,旋转后中心位置与原位置完全重合,视觉上整体位置不变,是最常用的旋转方式- 自定义旋转点:比如
(x,y),x取值范围0到Drawable宽度,y取值范围0到Drawable高度,旋转时这个点会固定在原位置,Drawable其余部分绕它旋转
内容的提问来源于stack exchange,提问作者CamaileeXD 305
相关产品推荐
相关产品推荐

