getGlobalVisibleRect和getLocalVisibleRect
在看android官网的demo的时候遇到这两个api,开始不是很明白这两个方法的作用。
通过多次的调试和测试之后慢慢开始有了点眉目,为了防止以后忘记,以此博文为记。
作为测试的目的,我写了这样一个布局
<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:id="@+id/container" tools:context=".MainActivity" android:paddingLeft="10px"> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:id="@+id/innerL" android:paddingLeft="20px">
<ImageView android:id="@+id/expandedImage" android:layout_width="wrap_content" android:src="@drawable/thumb1" android:layout_height="wrap_content"/> </LinearLayout> </RelativeLayout>
另外为了方便测试,我将虚拟机设置为1dp=1px,大小等于320x480
因为这两个方法在View对象里面,所以基本上继承自View的对象都可以使用。
也是为了方便自己,我使用ImageView作为测试对象,图片大小为160x120px
下面是我自己的一个测试过程:
因为getLocalVisibleRect只有一个参数,所以我从这个方法入手
代码如下
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ImageView imageView = (ImageView) findViewById(R.id.expandedImage); imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Rect localRect = new Rect(); imageView.getLocalVisibleRect(localRect); System.out.println("local" + localRect); } }); }
程序执行后Logcat输出:
localRect(0, 0 - 160, 120)
很明显localRect变量中的right和bottom正是图片的长和宽。
目前的结论是:getLocalVisibleRect(Rect r)方法可以把视图的长和宽映射到一个Rect对象上。
这里我们先放下这个方法,把注意力集中到getGlobalVisibleRect方法中。
将代码改为:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ImageView imageView = (ImageView) findViewById(R.id.expandedImage); imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Rect globalRect = new Rect(); imageView.getGlobalVisibleRect(globalRect); System.out.println("global" + globalRect); } }); }
Logcat输出:
globalRect(30, 81 - 190, 201)
除了30和190可以猜测出是什么(即left和right),其他的基本上没有什么线索,只知道是top和bottom。
30是paddingLeft,即图片向右偏移了30px,因此right很自然就多了30px
top和bottom要知道是什么,我用了最笨的办法,就是用尺子量。
可见,这81像素就是状态栏加上ActionBar的高度,所以Bottom120加上81就是201
目前的结论是:getGlobalVisibleRect方法的作用是获取视图在屏幕坐标系中的偏移量
那么,我的结论真的是正确的吗,其实我也不知道,继续测试下去。
把原先的布局文件改成下面这样的,现在我们重点对LinearLayout进行测试
<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:id="@+id/container" tools:context=".MainActivity"> <LinearLayout android:layout_width="320dp" android:layout_height="480dp" android:orientation="vertical" android:id="@+id/innerL" android:background="#550000ff" android:layout_marginLeft="-50px" android:layout_marginTop="30px"> </LinearLayout> </RelativeLayout>
布局效果如下:这种布局的目的是让这个View超出屏幕区域
java代码如下:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final LinearLayout ll = (LinearLayout) findViewById(R.id.innerL); ll.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Rect localRect = new Rect(); ll.getLocalVisibleRect(localRect); Rect globalRect = new Rect(); ll.getGlobalVisibleRect(globalRect); System.out.println("global" + globalRect); System.out.println("local" + localRect); } }); }
现在我们可以点击蓝色的这个布局获取数据,这次我们同时获取这两个方法返回的数据
Logcat数据:
globalRect(0, 111 - 271, 480)
localRect(49, 0 - 320, 369)
先来画图分析globalRect中的数据,在前面我们知道globalRect是基于屏幕坐标系的
从上图可以看出,蓝色区域的四个点的坐标实际上是LinearLayout在屏幕坐标系的可见区域
结论:
getGlobalVisibleRect方法的作用是获取视图在屏幕坐标中的可视区域
另外需要说的是,getGlobalVisibleRect还可以接受第二个Point类型的参数:
targetView.getGlobalVisibleRect(Rect r, Point gobalOffset)
调用完毕后,globalOffset的值就是targetView原点偏离屏幕坐标原点的距离。
现在来看localRect(49, 0 - 320, 369),初步猜测它是基于视图本身的坐标,
只要该视图没有被遮挡,targetView.getLocalVisibleRect()的坐标总是等于:
(0, 0, targetView.getwidth(), targetView.getheight())
从布局不难看出,我们让它向左偏移了50个像素,因此它本身的坐标也跟着向左移动50像素,
至于为什么是49,这个我也不太清楚。因为视图的top和right在该布局中总是可见,所以是0和320,
而bottom已经超出了屏幕, 所以480(屏幕的高度)-111(ActionBar+statusBar+marginTop)=369.
结论是:
getLocalVisibleRect的作用是获取视图本身可见的坐标区域,坐标以自己的左上角为原点(0,0)
最后测试图:
布局文件代码:
<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:id="@+id/container" tools:context=".MainActivity"> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:id="@+id/innerL"> <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/thumb1"/> </LinearLayout> <TextView android:id="@+id/local" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true"/> <TextView android:id="@+id/global" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/local" android:layout_below="@id/local"/> <TextView android:id="@+id/offset" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/local" android:layout_below="@id/global"/> </RelativeLayout>
程序逻辑:
package com.whathecode.zoomimage; import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; import android.widget.TextView; public class MainActivity extends ActionBarActivity { private int lastX = 0; private int lastY = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageView imageView = (ImageView) findViewById(R.id.img); imageView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = (int) event.getRawX(); lastY = (int) event.getRawY(); break; case MotionEvent.ACTION_MOVE: int dx = (int) event.getRawX() - lastX; int dy = (int) event.getRawY() - lastY; int left = v.getLeft() + dx; int top = v.getTop() + dy; int right = v.getRight() + dx; int bottom = v.getBottom() + dy; v.layout(left, top, right, bottom); lastX = (int) event.getRawX(); lastY = (int) event.getRawY(); Rect localRect = new Rect(); v.getLocalVisibleRect(localRect); ((TextView) findViewById(R.id.local)) .setText("local" + localRect.toString()); Rect globalRect = new Rect(); Point globalOffset = new Point(); v.getGlobalVisibleRect(globalRect, globalOffset); ((TextView) findViewById(R.id.global)) .setText("global" + globalRect.toString()); ((TextView) findViewById(R.id.offset)) .setText("globalOffset:" + globalOffset.x + "," + globalOffset.y); break; case MotionEvent.ACTION_UP: break; } return true; } }); } }