Android View各种尺寸位置相关的方法探究
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>
activity_collision_detection.xml
Activity:
package com.example.hellocollisiondetection; import com.mengdd.utils.Collision2DUtils; import android.os.Bundle;
import android.app.Activity;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ScrollView;
import android.widget.TextView; public class CollisionDetectionActivity extends Activity { private TextView mTouchTextView = null;
private TextView mResult1 = null; private View block1 = null;
private View block2 = null; private TextView mInfo1 = null;
private TextView mInfo2 = null; private ScrollView mScrollView = null; @Override
protected void onCreate(Bundle savedInstanceState) { // requestWindowFeature(Window.FEATURE_NO_TITLE);
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collision_detection);
mTouchTextView = (TextView) findViewById(R.id.touch);
mResult1 = (TextView) findViewById(R.id.result1); block1 = findViewById(R.id.block1);
block2 = findViewById(R.id.block2); mInfo1 = (TextView) findViewById(R.id.info1);
mInfo2 = (TextView) findViewById(R.id.info2); mScrollView = (ScrollView) findViewById(R.id.myScrollView); } @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.collision_detection, menu);
return true;
} @Override
public boolean onTouchEvent(MotionEvent event) { if (MotionEvent.ACTION_DOWN == event.getAction()) {
float x = event.getX();
float y = event.getY(); mTouchTextView.setText("x: " + x + ", y: " + y); Log.i("Touch", "x: " + x + ", y: " + y); detectCollision(x, y); getInfos(); }
return super.onTouchEvent(event);
} private void detectCollision(float x, float y) {
// Rect rect1 = new Rect(0, 0, 200, 200);
// boolean result1 = Collision2DUtils.isPointInRect((int)x, (int)y,
// rect1);
//
// RectF rect2 = new RectF(0,200,600,1000);
// boolean result2 = Collision2DUtils.isPointInRectF(x, y, rect2); boolean result1 = Collision2DUtils.isPointInView(x, y, block1); boolean result2 = Collision2DUtils.isPointInView(x, y, block2); Log.i("Touch", "result1: " + result1 + ", result2: " + result2);
mResult1.setText("result1: " + result1 + ", result2: " + result2);
} private void getInfos() { mInfo1.setText(getViewInfo(block1));
mInfo2.setText(getViewInfo(block2));
} private String getViewInfo(View view) {
StringBuffer stringBuffer = new StringBuffer(); int top = view.getTop();
int left = view.getLeft();
int right = view.getRight();
int bottom = view.getBottom();
int width = view.getWidth();
int height = view.getHeight(); stringBuffer.append("Info relative to Parent: " + "left: " + left
+ ", right: " + right + ", top: " + top + ", bottom: " + bottom
+ ", width: " + width + ", height: " + height); // API Level 11
stringBuffer.append("\n view.getTranslationX(): "
+ view.getTranslationX());
stringBuffer.append("\n view.getTranslationY(): "
+ view.getTranslationY()); Rect rect = new Rect();
view.getLocalVisibleRect(rect);
stringBuffer.append("\ngetLocalVisibleRect(): ");
stringBuffer.append("\n " + rect.toString()); Rect globalRect = new Rect();
view.getGlobalVisibleRect(globalRect);
stringBuffer.append("\ngetGlobalVisibleRect(): ");
stringBuffer.append("\n " + globalRect.toString()); int[] locationInWindow = new int[2];
view.getLocationInWindow(locationInWindow);
stringBuffer.append("\ngetLocationInWindow(): ");
stringBuffer.append("\n " + locationInWindow[0] + ", "
+ locationInWindow[1]); int[] locationOnScreen = new int[2];
view.getLocationOnScreen(locationOnScreen);
stringBuffer.append("\ngetLocationOnScreen(): ");
stringBuffer.append("\n " + locationOnScreen[0] + ", "
+ locationOnScreen[1]); return stringBuffer.toString();
} }
CollisionDetectionActivity.java
将两个有背景色的TextView的信息都获取并显示出来,注意此时是有标题栏的非全屏情况:
运行截图如下:
TextView1的信息:(在截图上加了红色的圈)

TextView2的信息:

说明:
getGlobalVisibleRect(Rect r)是可以得到绝对坐标的。
getLocationInWindow(int[] location)
getLocationOnScreen(int[] location)
这两个方法可以返回View左上角的绝对坐标。目前还不出有什么差别。
查看源码发现:
public void getLocationOnScreen(int[] location) {
getLocationInWindow(location);
final AttachInfo info = mAttachInfo;
if (info != null) {
location[0] += info.mWindowLeft;
location[1] += info.mWindowTop;
}
}
所以屏幕位置是在窗口位置上加了一个偏置。
Android View各种尺寸位置相关的方法探究的更多相关文章
- Android view中的requestLayout和invalidate方法
Android view中的requestLayout和invalidate方法 requestLayout:当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent v ...
- Android开发教程 - 使用Data Binding Android Studio不能正常生成相关类/方法的解决办法
本系列目录 使用Data Binding(一)介绍 使用Data Binding(二)集成与配置 使用Data Binding(三)在Activity中的使用 使用Data Binding(四)在Fr ...
- Android开发 获取View的尺寸的2个方法
前言 总所周知,在activity启动的onCreate或者其他生命周期里去获取View的尺寸是错误的,因为很有可能View并没有初始化测量绘制完成.你这个时候获取的宽或的高不出意外就是0.所以,我们 ...
- android View层的绘制流程
还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原理,记不记得 ...
- android view、viewgroup 事件响应拦截处理机制
文章中会用到部分网络资源,首先将原作者的链接附上. 但是还是会附上数量较大的关于此部分内容的自己的思考. ----------------------------------------------- ...
- Js位置与大小(1)——正确理解和运用与尺寸大小相关的DOM属性
在web开发中,不可避免遇到要计算元素大小以及位置的问题,解决这类问题的方法是利用DOM提供的一些API结合兼容性处理来,所有内容大概分3篇左右的文章的来说明.本文作为第一篇,介绍DOM提供的与尺寸大 ...
- android自定义控件(6)-详解在onMeasure()方法中如何测量一个控件尺寸
今天的任务就是详细研究一下protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法.如果只是说要重写什么方法有什么 ...
- Android:认识R类、findViewById方法查找组件、@string查找字符、@color查找颜色、@drawable查找图片、@dimen某个组件尺寸定义、项目引入资源国际化
导入 之前都是断断续续的看了一些于如何使用android开发的文章.资料等,到目前位置很多基础的东西都不清楚,于是去学习了别人的课程,才了认识了R类.findViewById方法查找组件.项目引入资源 ...
- android之在view中内嵌浏览器的方法
我要做的一个东西是在一个页面的中间嵌入浏览器,一开始不知道从哪里开始,因为以前用的都是Textveiw或者editVeiw之类的控件,而它们并不能用来显示网页的内容,怎么办呢? 首先想到的是:是不是有 ...
随机推荐
- GIF录制神器GifCam
前几天偶然看到一款神器:GifCam! GifCam是什么? 一款录制gif动画图片的小软件,小到不足一兆. 使用方法(简单到不可思议) 百度 GifCam 下载: 不用安装,直接打开gifcam: ...
- Tornado框架
Tornado介绍 Tornado 是 FriendFeed 使用的可扩展的异步非阻塞式 web 服务器及其相关工具的开源版本.这个 Web 框架看起来有些像web.py(豆瓣用这个写的) 或者 Go ...
- 关于Entity Framework中的Attached报错相关解决方案的总结
关于Entity Framework中的Attached报错的问题,我这里分为以下几种类型,每种类型我都给出相应的解决方案,希望能给大家带来一些的帮助,当然作为读者的您如果觉得有不同的意见或更好的方法 ...
- C#--声明类
- 微信开发系列----02:实现POST请求响应
继续昨天的,现在我们的微信测试成功了,可以开发实现微信的各种功能,今天主要实现微信的简单交互,比如发送语音,图片,文本等请求,网站服务器发送对应的响应. 项目GitHub地址: https://gi ...
- log4net 既要按日期分割日志文件,又要按文件大小分割。
<appender name="DebugAppender" type="log4net.Appender.RollingFileAppender"> ...
- 【原创】验证代理IP是否有用
/// <summary> /// 验证代理IP是否有用 /// </summary> /// <param name="ip">IP地址< ...
- C#串口通信
通过COM1发送数据,COM2接收数据.当COM2接收完本次发送的数据后,向COM1发送信息通知COM1本次数据已发完,COM1接到通知后,再发下一段数据.这样可以确保每次发送的数据都可以被正确接收. ...
- 使用JSLint提高JS代码质量
随着富 Web 前端应用的出现,开发人员不得不重新审视并重视 JavaScript 语言的能力和使用,抛弃过去那种只靠“复制 / 粘贴”常用脚本完成简单前端任务的模式.JavaScript 语言本身是 ...
- ExtJs动态生成treepanel的Json格式
在节点中加上"checked"属性,会自动生成checkbox. 获取选中节点 var nodeArray = ""; var nodesObj = mytre ...