View坐标,MotionEvent坐标, 二者的转换,可视区域

MotionEvent event

getX(),  getY() 是表示View相对于自身左上角的 x,y 坐标.  不是屏幕可见区域的坐标,而是以view左上角为原点(0,0)的坐标系。

getRawX(),getRawY() 是表示相对于屏幕左上角的 x 坐标值(注意:这个屏幕左上角是手机屏幕左上角, 不管activity是否有titleBar或是否全屏幕)。

 -------------------------------------------------------------------------------------------------------------------------------------

//获取View在当前屏幕内的绝对坐标, 相当于view的左上角的点在屏幕坐标系的坐标。计算该视图在全局坐标系中的x,y值,(注意这个值是要从屏幕顶端算起,也就是索包括了通知栏的高度)

final int[] location = new int[2];   

view.getLocationOnScreen(location);  

Event 的 getX、 getY,getRawX、getRawY 可以通过 getLocationOnScreen 来进行转换:

getX ()     ==     getRawX() - location[0]

getY ()     ==     getRawY() - location[1]

//使用例子:

//ListView的滚动条位置

lstView.setOnItemClickListener(new OnItemClickListener(){
 public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3){
  int Pos[] = { -1, -1 }; //保存当前坐标的数组
  arg1.getLocationOnScreen(Pos); //获取选中的 Item 在屏幕中的位置,以左上角为原点 (0, 0)
  OldListY = (float) Pos[1]; //我们只取 Y 坐标就行了
  }
});

在 setAdapter() 后恢复先前的位置: 

lstView.setAdapter(adapter); // 重新绑定Adapter   

lstView.setSelectionFromTop(index, (int) OldListY); // 恢复刚才的位置  

 ------------------------------------------

Viwe的getLeft , getTop, getBottom, getRight,  这一组是获取View在直接父布局坐标系中的位置。

以父布局的左上角位置为原点的坐标系,bottom是view的底边在y轴上的位置,同理getTop是获得view的顶部在父坐标系y轴上的位置。

可能为负数。 可用于判断listView是否滑到最顶部:list.getChildAt(0).getTop() == 0

--------------------------------------------

getWidth, getHeight, View的长和宽, 是屏幕上可见的view的大小(布局文件指定)padding的大小是包含在width和height里面的,设置pading不会影响该view的widht和height

public final int getHeight() {
  return mBottom - mTop;
}

--------------------------------------------

Rect r1 = new Rect();
view.getLocalVisibleRect(r1);      //以该view的左上角点为坐标原点,该view的可视区域。

获取view的rect, left 和top为0, right和bottom是view的宽和高,相当于getWidth,getHeight

--------------------------------------------

Rect r2 = new Rect();
view.getGlobalVisibleRect(r2);    // 获取view的各边在屏幕全局坐标系的位置,相当于getLeft等这一组函数,只是坐标系不一样。

-------------------------------------------

getScrollX, Return the scrolled left position of this view. This is the left edge of the displayed part of your view,in pixels.

view实际内容占的大小(画布上画的内容)可能远远超过其显示区域的大小(view布局大小),ScrollX,是当前显示区域的左边界在画布坐标系中的位置。

getScrollY, 同上。

scrollBy,scrollTo,移动画布,在画布坐标系上移动x,y轴位置,调整显示区域。

scrollBy(20)相当于画布向左移动了20px

 

 -----------------------------------------------------------------------------------

源码中,由用户的点击事件坐标,找到目标view的过程:

在父view中根据event的坐标,计算处在那个子view的范围 :
Rect rect
= new Rect();
mImg.getHitRect(rect); //得到的是在父坐标中的响应区域,可结合event.getX event.getY 来判断点击在哪个子view的响应范围内 rect.contains(x, y); /** * Hit rectangle in parent's coordinates * * @param outRect The hit rectangle of the view. */ public void getHitRect(Rect outRect) {   outRect.set(mLeft, mTop, mRight, mBottom); }
public boolean dispatchTouchEvent(MotionEvent ev) {

    final float xf = ev.getX();   //view 的屏幕坐标,如果view没有scroll,是和画布坐标重合的
    final float yf = ev.getY();
    final float scrolledXFloat = xf + mScrollX;  //加上滚动的值,转换为view的画布的坐标,这个坐标系是onMeasure和onLayout时用的坐标
    final float scrolledYFloat = yf + mScrollY;  

    final Rect frame = mTempRect;

    final int scrolledXInt = (int) scrolledXFloat;
    final int scrolledYInt = (int) scrolledYFloat;
    
    final View[] children = mChildren;
    final int count = mChildrenCount; 
    for (int i = count - 1; i >= 0; i--) {   //遍历子view
        final View child = children[i];
        child.getHitRect(frame);     //返回该子view的mLeft, mTop, mRight, mBottom值,这些值是onLayout的时候设上去的
        if (frame.contains(scrolledXInt, scrolledYInt)) { // 事件坐标是否落在该子view区域内
            // offset the event to the view's coordinate system
            final float xc = scrolledXFloat - child.mLeft;  //将事件的坐标由父view坐标系,转为子view的坐标系(都是画布坐标系)
            final float yc = scrolledYFloat - child.mTop;
            ev.setLocation(xc, yc);
            child.dispatchTouchEvent(ev)
        }
    }
}

 

 

 

 

 

 

 

 

 

 

原文地址:https://www.cnblogs.com/zijianlu/p/2475645.html