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方法:

getTranslationX()

getTranslationY()

getLocalVisibleRect(Rect r)

getGlobalVisibleRect(Rect r)

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各种尺寸位置相关的方法探究的更多相关文章

  1. Android view中的requestLayout和invalidate方法

    Android view中的requestLayout和invalidate方法 requestLayout:当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent v ...

  2. Android开发教程 - 使用Data Binding Android Studio不能正常生成相关类/方法的解决办法

    本系列目录 使用Data Binding(一)介绍 使用Data Binding(二)集成与配置 使用Data Binding(三)在Activity中的使用 使用Data Binding(四)在Fr ...

  3. Android开发 获取View的尺寸的2个方法

    前言 总所周知,在activity启动的onCreate或者其他生命周期里去获取View的尺寸是错误的,因为很有可能View并没有初始化测量绘制完成.你这个时候获取的宽或的高不出意外就是0.所以,我们 ...

  4. android View层的绘制流程

    还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原理,记不记得 ...

  5. android view、viewgroup 事件响应拦截处理机制

    文章中会用到部分网络资源,首先将原作者的链接附上. 但是还是会附上数量较大的关于此部分内容的自己的思考. ----------------------------------------------- ...

  6. Js位置与大小(1)——正确理解和运用与尺寸大小相关的DOM属性

    在web开发中,不可避免遇到要计算元素大小以及位置的问题,解决这类问题的方法是利用DOM提供的一些API结合兼容性处理来,所有内容大概分3篇左右的文章的来说明.本文作为第一篇,介绍DOM提供的与尺寸大 ...

  7. android自定义控件(6)-详解在onMeasure()方法中如何测量一个控件尺寸

    今天的任务就是详细研究一下protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法.如果只是说要重写什么方法有什么 ...

  8. Android:认识R类、findViewById方法查找组件、@string查找字符、@color查找颜色、@drawable查找图片、@dimen某个组件尺寸定义、项目引入资源国际化

    导入 之前都是断断续续的看了一些于如何使用android开发的文章.资料等,到目前位置很多基础的东西都不清楚,于是去学习了别人的课程,才了认识了R类.findViewById方法查找组件.项目引入资源 ...

  9. android之在view中内嵌浏览器的方法

    我要做的一个东西是在一个页面的中间嵌入浏览器,一开始不知道从哪里开始,因为以前用的都是Textveiw或者editVeiw之类的控件,而它们并不能用来显示网页的内容,怎么办呢? 首先想到的是:是不是有 ...

随机推荐

  1. Spring Boot异常处理详解

    在Spring MVC异常处理详解中,介绍了Spring MVC的异常处理体系,本文将讲解在此基础上Spring Boot为我们做了哪些工作.下图列出了Spring Boot中跟MVC异常处理相关的类 ...

  2. jQuery.Data源码

    jQuery.data的是jQuery的数据缓存系统.它的主要作用就是为普通对象或者DOM元素添加数据. 1 内部存储原理 这个原理很简单,原本要添加在DOM元素本身的数据,现在被集中的存储在cach ...

  3. eclipse中断点调试debug

    几乎没有用过debug模式,每次想要知道结果都是sysou一下.记得曾经问乱码问题,jfinal说打断点调试看在哪里出错.简单记下普通调试. 1.在需要查看的地方打断点,方法是在行号右侧双击. 2.运 ...

  4. nodejs学习笔记二——链接mongodb

    a.安装mongoose库用来链接mongodb数据库 安装mongodb数据库参考mongodb安装 前言(怨言) 本来是想安装mongodb库来链接mongodb的,命令行到nodejs工程目录: ...

  5. log4net的配置详解

    log4net是一款优秀的第三方日志框架,可以很容易的加载到开发项目中(引用log4net的dll,再配置些基本参数即可),帮助程序员把日志信息输出到各种不同的目标,常见的有文本.数据库.window ...

  6. ASP.NET MVC Layout 嵌套

    模板页Layout.cshtml代码(路径"~/Views/Backstage/MachineMng/Layout.cshtml"): @{ ViewBag.Title = &qu ...

  7. 分享15个HTML5工具

    HTML5 Working Draft Specification HTML5 Working Draft Specification译为HTML 5工作草案标准,它是 HTML5 的最新草案,由 W ...

  8. C#编程总结(七)数据加密——附源码

    C#编程总结(七)数据加密——附源码 概述 数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,通常称为“密文”,使其只能在输入相应的密钥之后才能显示出本来内容 ...

  9. iOs 自定义UIView 日历的实现 Swift2.1

    学习Swift有一个月了,动手写一个UIView吧. 所有源代码在最后,直接用就可以了,第一次写Swift,和C#,Java还是有区别的 (博客园可以考虑在代码插入中添加Swift的着色了) 1  函 ...

  10. PHP程序的常见漏洞攻击分析

    综述:PHP程序也不是固若金汤,随着PHP的广泛运用,一些黑客们也在无时不想找PHP的麻烦,通过PHP程序漏洞进行攻击就是其中一种.在节,我们将从全局变量,远程文件,文件上载,库文件,Session文 ...