Android View各种尺寸位置相关的方法探究
本来想做一个View间的碰撞检测之类的。
动手做了才发现不是想象的那么简单。
首先,写好了碰撞检测的工具类如下:
package com.mengdd.utils; import android.graphics.Rect; import android.graphics.RectF; import android.util.Log; import android.view.View; public class Collision2DUtils { public static boolean isPointInRect(int x, int y, Rect rect) { boolean isIn = false; isIn = rect.contains(x, y); return isIn; } public static boolean isPointInRectF(float x, float y, RectF rectF) { boolean isIn = false; isIn = rectF.contains(x, y); return isIn; } public static boolean isPointInView(float x, float y, View view) { if (null == view) { throw new IllegalArgumentException("view is null!"); } boolean isIn = false; int top = view.getTop(); int left = view.getLeft(); int right = view.getRight(); int bottom = view.getBottom(); int width = view.getWidth(); int height = view.getHeight(); if (x >= left && x <= right && y >= top && y <= bottom) { isIn = true; } Log.i("View", ", x: " + x + ", left: " + left + ", right: " + right + ", y: " + y + ", top: " + top + ", bottom: " + bottom + ", width: " + width + ", height: " + height + ", result: " + isIn); return isIn; } }
三个方法,分别用于判断点是否在一个矩形中(整形,浮点型),还有判断一个点是否在一个View显示的范围中。
然后测试了一下前两个方法,因为矩形对象都是自己直接用数字构建的,所以没有问题。
测试判断点是否在View中的方法
思路是:在布局中写两个TextView,在Activity中重写onTouchEvent方法,判断点击的点是否在View中。
@Override public boolean onTouchEvent(MotionEvent event) { if (MotionEvent.ACTION_DOWN == event.getAction()) { float x = event.getX(); float y = event.getY(); detectCollision(x, y); } return super.onTouchEvent(event); }
其中判断的方法:
结果显示在另一个TextView里
private void detectCollision(float x, float y) { boolean result1 = Collision2DUtils.isPointInView(x, y, block1); boolean result2 = Collision2DUtils.isPointInView(x, y, block2); mResult1.setText("result1: " + result1 + ", result2: " + result2); }
一试就发现问题了:判断结果并不对。
判断错误的原因:
onTouchEvent()回调中获取的坐标值,是点击位置,是在绝对坐标中的。
碰撞检测方法中View的getTop()、getBottom()、getLeft()、getRight()获取的都是当前View相对于它的父类容器的顶部、底部、左边和右边的位置。
因为一个是绝对位置一个是相对位置,所以无法比较。
当然也有可以比较的情况,就是这个View的父类充满了整个屏幕,然后窗口的设置是无标题并且全屏的。
在onCreate()方法中添加如下语句设置无标题全屏:
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
那如何获取View的绝对位置呢?
逐一看了看View中与位置相关的几个get方法:
getGlobalVisibleRect(Rect r, Point globalOffset)
getLocationInWindow(int[] location)
getLocationOnScreen(int[] location)
完整Demo如下:
布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".CollisionDetectionActivity" > <TextView android:id="@+id/touch" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" /> <TextView android:id="@+id/result1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="#FFBBBBFF" android:textSize="20sp" /> <TextView android:id="@+id/block1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/touch" android:background="#FFFFBBFF" android:padding="10dp" android:text="Touch Block1" android:textSize="20sp" /> <TextView android:id="@+id/block2" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/block1" android:background="#FFBBFFBB" android:padding="10dp" android:text="Touch Block2" android:textSize="20sp" /> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@id/result1" android:layout_below="@id/block2" android:id="@+id/myScrollView"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/info1" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:textSize="20sp" /> <TextView android:id="@+id/info2" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:textSize="20sp" /> </LinearLayout> </ScrollView> </RelativeLayout>