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

OnTouch创建ImageView位置偏移及自定义RelativeLayout边界限制问题

问题解决:ImageView位置偏移与拖动边界限制

我来帮你搞定这两个问题,咱们逐个分析解决:

一、解决ImageView触摸位置偏移的问题

你现在用event.getRawX()/event.getRawY()来设置ImageView的位置,这两个方法获取的是相对于屏幕左上角的坐标,但FloorplanView作为RelativeLayout,它的子View的坐标应该是相对于FloorplanView自身左上角的,这就是位置偏移的核心原因。

另外,直接设置setX()/setY()会让ImageView的左上角对齐触摸点,如果想让星形的中心和触摸点重合,还需要减去ImageView自身宽高的一半。

修改FloorplanTouchListener的ACTION_UP部分:

case MotionEvent.ACTION_UP:
    ImageView img = new ImageView(getContext());
    img.setOnTouchListener(new FlagTouchListener());
    img.setBackground(getResources().getDrawable(android.R.drawable.btn_star));
    // 先测量ImageView的尺寸,不然getWidth/getHeight会返回0
    img.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
    int imgWidth = img.getMeasuredWidth();
    int imgHeight = img.getMeasuredHeight();
    // 使用相对于FloorplanView的坐标,让中心对齐触摸点
    float x = event.getX() - imgWidth / 2f;
    float y = event.getY() - imgHeight / 2f;
    img.setX(x);
    img.setY(y);
    addView(img);
    break;

二、实现拖动ImageView时的边界限制

我们需要给ImageView的触摸监听器FlagTouchListener添加拖动逻辑,并在拖动过程中检查位置是否超出FloorplanView的边界:

public class FlagTouchListener implements View.OnTouchListener {
    private float offsetX, offsetY;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        FloorplanView parentView = (FloorplanView) v.getParent();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 记录触摸点相对于ImageView左上角的偏移量
                offsetX = event.getRawX() - v.getX();
                offsetY = event.getRawY() - v.getY();
                // 提升当前ImageView的层级,避免被其他View遮挡
                parentView.bringChildToFront(v);
                break;
            case MotionEvent.ACTION_MOVE:
                // 计算ImageView的目标位置
                float targetX = event.getRawX() - offsetX;
                float targetY = event.getRawY() - offsetY;

                // 计算边界限制
                float minX = 0;
                float maxX = parentView.getWidth() - v.getWidth();
                float minY = 0;
                float maxY = parentView.getHeight() - v.getHeight();

                // 限制X坐标在[minX, maxX]范围内
                targetX = Math.max(minX, Math.min(targetX, maxX));
                // 限制Y坐标在[minY, maxY]范围内
                targetY = Math.max(minY, Math.min(targetY, maxY));

                // 更新ImageView的位置
                v.setX(targetX);
                v.setY(targetY);
                break;
        }
        return true;
    }
}

额外优化点

  1. 在FloorplanView的构造方法中,建议添加setClipChildren(true),这样子View超出FloorplanView的部分会被裁剪,更符合预期:
public FloorplanView(Context context, AttributeSet attrs) {
    super(context, attrs);
    SCROLL_THRESHOLD = getResources().getDimensionPixelSize(R.dimen.margin5);
    setClipChildren(true); // 修改为true,裁剪超出边界的子View
    setOnTouchListener(new FloorplanTouchListener());
}
  1. 如果你的SCROLL_THRESHOLD变量没有定义,记得添加成员变量:
private int SCROLL_THRESHOLD;

这样修改后,你触摸FloorplanView时,星形ImageView会准确出现在触摸位置(中心对齐),拖动时也不会超出FloorplanView的边界了。

内容的提问来源于stack exchange,提问作者SingleWave Games

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:28:47