如何通过拖动边缘结合动态Pivot实现View尺寸调整?
Android旋转ViewGroup拖动边缘调整尺寸的位置偏移问题
问题描述
我有一个ViewGroup,需要通过拖动其边缘来调整尺寸。目前已成功实现拖动边角调整View尺寸的功能,但当View处于旋转状态时,拖动右侧边缘调整宽度时,View无法保持原有位置。我将PivotX和PivotY设置为0来固定View,但在View旋转时会出现问题;缩放结束后重置Pivot,又会因将Pivot设为View中心导致View跳动。
视图效果:旋转后的ViewGroup带有右侧拖动手柄,拖动手柄调整宽度时位置偏移
原触摸事件代码
public boolean onTouch(View v, MotionEvent event) { if (event.getPointerCount() > 1) { return true; } int x_cord = (int) event.getRawX(); int y_cord = (int) event.getRawY(); layBg = (RelativeLayout) getParent(); LayoutParams layoutParams = (LayoutParams) layGroup.getLayoutParams(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: v.setPressed(true); basex = x_cord; basey = y_cord; basew = layGroup.getWidth(); baseh = layGroup.getHeight(); layGroup.getLocationOnScreen(new int[2]); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: v.setPressed(false); layGroup.resetPivot(); break; case MotionEvent.ACTION_MOVE: int currx = x_cord; int curry = y_cord; float angle = (float) Math.toDegrees(Math.atan2(curry - basey, currx - basex)); if (angle < 0.0f) { angle += 360.0f; } int changesW = currx - basex; int changesH = curry - basey; changesW = (int) (Math.sqrt((changesW * changesW) + (changesH * changesH)) * Math.cos(Math.toRadians(angle - layGroup.getRotation()))); int width = (changesW * 2) + basew; if (v.getId() == R.id.rightHandle) { if (width > 200) { layGroup.setPivotX(0); layGroup.setPivotY(0); int old_width = layoutParams.width; layoutParams.width += width - old_width; layGroup.setLayoutParams(layoutParams); } } break; } return false; }
修复方案
核心问题
旋转状态下直接修改布局宽高+固定(0,0)Pivot的逻辑存在两个问题:
- 旋转后的坐标系变换导致(0,0)Pivot不再是视觉上的左侧固定点,调整宽度时View位置偏移
- 结束时重置Pivot到中心,会因尺寸变化触发View位置跳动
修改后的代码
public boolean onTouch(View v, MotionEvent event) { if (event.getPointerCount() > 1) { return true; } int x_cord = (int) event.getRawX(); int y_cord = (int) event.getRawY(); RelativeLayout layBg = (RelativeLayout) getParent(); RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layGroup.getLayoutParams(); // 存储初始全局坐标和尺寸 int[] groupLocation = new int[2]; int baseLeft, baseTop; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: v.setPressed(true); basex = x_cord; basew = layGroup.getWidth(); // 获取ViewGroup在屏幕上的初始位置 layGroup.getLocationOnScreen(groupLocation); baseLeft = groupLocation[0]; baseTop = groupLocation[1]; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: v.setPressed(false); // 取消重置Pivot操作,避免位置跳动 break; case MotionEvent.ACTION_MOVE: if (v.getId() == R.id.rightHandle) { // 计算全局坐标系下的水平拖动偏移 int deltaX = x_cord - basex; float rotation = layGroup.getRotation(); // 结合旋转角度,计算实际需要调整的宽度 float adjustedWidthDelta = deltaX * (float) Math.cos(Math.toRadians(rotation)); int newWidth = (int) (basew + adjustedWidthDelta); if (newWidth > 200) { // 设置Pivot为左侧边缘中点,确保旋转时左侧位置固定 layGroup.setPivotX(0); layGroup.setPivotY(layGroup.getHeight() / 2f); // 更新宽度 layoutParams.width = newWidth; // 修正View位置:旋转后宽度变化会带动偏移,反向修正leftMargin float offsetX = adjustedWidthDelta * (float) Math.sin(Math.toRadians(rotation)) / 2f; layoutParams.leftMargin = (int) (baseLeft - offsetX); layoutParams.topMargin = baseTop; layGroup.setLayoutParams(layoutParams); } } break; } return true; }
关键优化点
- 固定Pivot到左侧中点:旋转时拖动右侧边缘,视觉上左侧位置保持不动,符合操作预期
- 全局坐标系计算:用屏幕坐标计算偏移,避免旋转后局部坐标系的混乱
- 移除Pivot重置:不需要在操作结束时改回中心Pivot,彻底避免跳动
- 位置偏移修正:通过三角函数计算旋转带来的位置偏移,反向调整margin,保证View位置稳定
内容的提问来源于stack exchange,提问作者Rajesh android developer
相关产品推荐
相关产品推荐

