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; } }
额外优化点
- 在
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()); }
- 如果你的
SCROLL_THRESHOLD变量没有定义,记得添加成员变量:
private int SCROLL_THRESHOLD;
这样修改后,你触摸FloorplanView时,星形ImageView会准确出现在触摸位置(中心对齐),拖动时也不会超出FloorplanView的边界了。
内容的提问来源于stack exchange,提问作者SingleWave Games
相关产品推荐
相关产品推荐

