彻底了解View 的坐标关系

View 坐标的关系

只写结论,不贴一大推的源码啥的,简单使用的技巧才是王道(可以自行去检测对与错(当然是不会错的))

一:看完本篇文章你会明白一下问题

(1):View 的 getLeft()和get Right()和 getTop() 和getBottom()

(2)View 的 getY(), getTranslationY() 和 getTop() 之间的联系

(3)View 的 getScroolY 和 View 的 scrollTo() 和 scrollBy()

(4)event.getY 和 event.getRawY()

(5)扩展,怎样获取状态栏(StatusBar)和标题栏(titleBar)的高度

二:以下问题

(1):View 的 getLeft()和get Right()和 getTop() 和getBottom()?

View.getLeft() ;
View.getTop() ;
View.getBottom();
View.getRight() ; 

top是左上角纵坐标,left是左上角横坐标,right是右下角横坐标,bottom是右下角纵坐标,都是相对于它的直接父***View而言的,而不是相对于屏幕而言的。这一点要区分清楚*。那那个坐标是相对于屏幕而言的呢,以及要怎样获取相对于屏幕的坐标呢?
有两种方式
方式一:onWindowFocusChanged()方法里面进行调用

   @Override
    public void onWindowFocusChanged(boolean hasFocus) {
     super.onWindowFocusChanged(hasFocus); 
     //确保只会调用一次
      if(first){
        first=false;
        final int[] location = new int[2];     
        mView.getLocationOnScreen(location);
        int x1 = location[0]  ;
        int y1 = location[1]  ;
        Log.i(TAG, "onCreate: x1=" +x1);
        Log.i(TAG, "onCreate: y1=" +y1);
      }
   }

方式二:在视图树绘制完成的时候进行测量

  mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver
                .OnGlobalLayoutListener() {

            @Override
            public void onGlobalLayout() {
                //   移除监听器,确保只会调用一次,否则在视图树发挥改变的时候又会调用
                mView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                final int[] location = new int[2];
                mView.getLocationOnScreen(location);
                int x1 = location[0];
                int y1 = location[1];
                Log.i(TAG, "onCreate: x1=" + x1);
                Log.i(TAG, "onCreate: y1=" + y1);
            }
        });

(2):View 的 getY(), getTranslationY() 和 getTop() 之间的关联?

结论:getY()= getTranslationY()+ getTop ()而 getTranslationY() 的默认值是0,除非我们通过 setTranlationY() 来改变它,这也就是我们上面上到的 getY 默认值跟 getTop()相同那我们要怎样改变 top值 和 Y 值呢? 很明显就是调用相应的set方法 ,即 setY() 和setTop() ,就可以改变他们 的值。

(3):View 的 getScroolY 和 View 的 scrollTo() 和 scrollBy()?

结论:getScrollY是一个比较特别的函数,因为它涉及一个值叫mScrollY,简单说,getScrollY一般得到的都是0,除非你调用过scrollTo或scrollBy这两个函数来改变它
从字面意思我们可以知道 scrollTo() 是滑动到哪里的意思 ,scrollBy()是相对当前的位置滑动了多少
注意:有几点需要注意的是
不论是scrollTo或scrollBy,其实都是对View的内容进行滚动而不是对View本身,你可以做个小实验,一个LinearLayouy背景是黄色,里面放置一个子LinearLayout背景是蓝色,调用scrollTo或scrollBy,移动的永远是蓝色的子LinearLayout。
还有就是scrollTo和scrollBy函数的参数和坐标系是“相反的”,比如scrollTo(-100,0),View的内容是向X轴正方向移动的,这个相反打引号是因为并不是真正的相反,

(4)event.getY() 和 event.getRawY()

结论:要区分于MotionEvent.getRawX() 和MotionEvent.getX();
在public boolean onTouch(View view, MotionEvent event) 中,当你触到控件时,x,y是相对于该控件左上点(控件本身)的相对位置。 而rawx,rawy始终是相对于屏幕的位置。getX()是表示Widget相对于自身左上角的x坐标,而getRawX()是表示相对于屏幕左上角的x坐标值 (注意:这个屏幕左上角是手机屏幕左上角,不管activity是否有titleBar或是否全屏幕)。

上一张图
这里写图片描述

(5)怎样获取状态栏(StatusBar)和标题栏(titleBar)的高度

直接上代码:
注意点:这里我们需要注意的 是在ActionBar存在的情况下,通过这种方法我们才能够得出titleBar的高度,否则是无法得到的,因为viewTop 为0.


     public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);

        //屏幕
        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        Log.e(TAG, "屏幕高:" + dm.heightPixels);

        //应用区域
        Rect outRect1 = new Rect();
        getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect1);
        //这个也就是状态栏的 高度
        Log.e(TAG, "应用区顶部" + outRect1.top);

        Log.e(TAG, "应用区高" + outRect1.height());

        // 这个方法必须在有actionBar的情况下才能获取到状态栏的高度
        //View绘制区域
        Rect outRect2 = new Rect();
        getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(outRect2);
        Log.e(TAG, "View绘制区域顶部-错误方法:" + outRect2.top);   //不能像上边一样由outRect2.top获取,这种方式获得的top是0,可能是bug吧
        Log.e(TAG, "View绘制区域高度:" + outRect2.height());

        int viewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();   //要用这种方法
        Log.e(TAG, "View绘制区域顶部-正确方法:" + viewTop);

        int titleBarHeight=viewTop;

        Log.d(TAG, "onWindowFocusChanged: 标题栏高度titleBarHeight=" +titleBarHeight);

    }

猜你喜欢

转载自blog.csdn.net/tongzhengtong/article/details/54139265
今日推荐