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;
            }
        });

    }
}
时间: 2024-09-27 02:23:00

getGlobalVisibleRect和getLocalVisibleRect的相关文章

AnimationsDemo中的ZoomActivity代码分析

AnimationsDemo是android官网的一个动画使用示例. ZoomActivity是demo中的图像缩放动画,因为这种效果比较常见,所以研究了一下代码. 下面是效果图: 毫无疑问这是一个组合动画,translation和scale动画.实现这种动画的关键是如何确定动画的坐标和缩放比例 除了一些简单的数学计算外,该demo还利用了ImageView的fitCenter特性.稍后我们就可以看到. 在开始分析代码之前,先说一下程序的原理:     1,点击缩略图的时候同时将缩略图隐藏.  

安卓坐标

1 说来说去都不如 画图示意 简单易懂啊!!!真是的! 来吧~~先上张图~~! 2 3 4 (一)首先明确一下 Android 中的坐标系统 : 5 屏幕的左上角是坐标系统原点(0,0) 6 原点向右延伸是X轴正方向,原点向下延伸是Y轴正方向 7 8 (二)关于Scroll: 屏幕显示的内容很多时,会有超出一屏的情况,于是就产生了Scroll的概念. 9 10 在View类中有个方法: 11 getScrollY() 英文原文描述是: 12 Return the scrolled top pos

Android坐标

说来说去都不如 画图示意 简单易懂啊!!!真是的! 来吧~~先上张图~~! (一)首先明确一下 android 中的坐标系统 : 屏幕的左上角是坐标系统原点(0,0) 原点向右延伸是X轴正方向,原点向下延伸是Y轴正方向 (二)关于Scroll: 屏幕显示的内容很多时,会有超出一屏的情况,于是就产生了Scroll的概念. 在View类中有个方法: getScrollY()  英文原文描述是: Return the scrolled top position of this view. This i

android应用程序中获取view 的位置

1. 相对位置: getLeft() , getRight(), getTop(), getBottom() 在Android中可以把left相当于X轴值, top相当于Y轴值, 通过这两个值Android系统可以知道视图的绘制起点,在通过Wdith 和 Height 可以得到视图上下左右具体值,就可以在屏幕上绝对位置绘制视图.right 与 bottom计算如下: right = left + width; bottom = top + height; 视图左侧位置  view.getLeft

android tv gridview焦点放大效果

在tv上开发gridview有焦点放大这个效果还是很普遍的做法,今天就讲下这个实现方案,当然要实现这个效果有很多种,我这里只是讲其中的一种实现方案,也是比较简单而且容易看懂的一个,首先看下效果图是怎么样的? 这个肯定也许会这么想我选中了那个item就设置一张焦点框图片就可以实现,告诉你没这么简单,这个框是根据你选中了那个item而动态画上去的,而画的位置是要获取item view的坐标的,我准备把这个用到的知识点分开一点点讲,然后再合拼起来,首先说下怎么把一个背景图画上去,我们知道自定义一个vi

android应用程序中获取view的位置

获取View类界面控件的位置,有助于添加新的控件. 获取在parent里的相对坐标位置   这个比较简单,不用多说,直接调用View的方法:getLeft , getTop, getBottom, getRight获得. 获取在屏幕中的绝对位置 getLocalVisibleRect getGlobalVisibleRect 这个方法是构建一个Rect用来"套"这个view.此Rect的坐标是相对当前activity而言. 若是普通activity,则Rect的top为可见的状态栏高度

Android应用坐标系统全面具体解释

1 背景 去年有非常多人私信告诉我让说说自己定义控件,事实上通观网络上的非常多博客都在讲各种自己定义控件,可是大多数都是授之以鱼.却非常少有较为系统性授之于渔的文章,同一时候由于自己也迟迟没有时间规划这一系列文章,近期想将这一系列文章又一次提起来,所以就来先总结一下自己定义控件的一个核心知识点--坐标系. 非常多人可能不屑一顾Android的坐标系.可是假设你想彻底学会自己定义控件,我想说了解Android各种坐标系及一些API的坐标含义绝对算一个小而不可忽视的技能.所谓Android自己定义V

可清空文本的EditText

代码如下: 1 public class DeleteEditText extends EditText { 2 3 private Context mContext; 4 5 //删除图标 6 private Drawable drawableDelete; 7 8 public DeleteEditText(Context context) { 9 super(context); 10 mContext = context; 11 init(); 12 } 13 14 public Dele

在滚动列表中实现视频的播放(ListView &amp; RecyclerView)

英文原文:Implementing video playback in a scrolled list (ListView & RecyclerView) 本文将讲解如何在列表中实现视频播放.类似于诸如 Facebook, Instagram 或者 Magisto这些热门应用的效果: Facebook: Magisto: Instagram: 这片文章基于开源项目: VideoPlayerManager. 所有的代码和示例都在那里.本文将跳过许多东西.因此如果你要真正理解它是如何工作的,最好下载