zoukankan      html  css  js  c++  java
  • 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 + ", 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 + ", height: " + height);
    
            // API Level 11
            stringBuffer.append("
     view.getTranslationX(): "
                    + view.getTranslationX());
            stringBuffer.append("
     view.getTranslationY(): "
                    + view.getTranslationY());
    
            Rect rect = new Rect();
            view.getLocalVisibleRect(rect);
            stringBuffer.append("
    getLocalVisibleRect(): ");
            stringBuffer.append("
     " + rect.toString());
    
            Rect globalRect = new Rect();
            view.getGlobalVisibleRect(globalRect);
            stringBuffer.append("
    getGlobalVisibleRect(): ");
            stringBuffer.append("
     " + globalRect.toString());
    
            int[] locationInWindow = new int[2];
            view.getLocationInWindow(locationInWindow);
            stringBuffer.append("
    getLocationInWindow(): ");
            stringBuffer.append("
     " + locationInWindow[0] + ", "
                    + locationInWindow[1]);
    
            int[] locationOnScreen = new int[2];
            view.getLocationOnScreen(locationOnScreen);
            stringBuffer.append("
    getLocationOnScreen(): ");
            stringBuffer.append("
     " + 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;
            }
        }

      所以屏幕位置是在窗口位置上加了一个偏置。

  • 相关阅读:
    0923------APUE 学习笔记----------Linux系统的启动流程
    0915-----Linux设备驱动 学习笔记----------一个简单的字符设备驱动程序
    0815------算法笔记----------矩阵连乘问题
    0806------Linux网络编程----------Echo 网络库 学习笔记
    事件学习
    信息系统需求分析阶段的实践经验之二---如何有效地获得用户需求【转】
    信息系统需求分析阶段的实践经验之一---需求分析概述[转]
    Lambda表达式【转】
    C#委托的介绍(delegate、Action、Func、predicate)【转】
    css3选择器——导图篇
  • 原文地址:https://www.cnblogs.com/mengdd/p/3273284.html
Copyright © 2011-2022 走看看