You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过拖动边缘结合动态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的逻辑存在两个问题:

  1. 旋转后的坐标系变换导致(0,0)Pivot不再是视觉上的左侧固定点,调整宽度时View位置偏移
  2. 结束时重置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 16:43:56