Android中的获取控件矩阵gethitrect方法

来源:互联网 发布:办卡软件 编辑:程序博客网 时间:2024/05/29 05:56

原文地址:http://souly.cn/%E6%8A%80%E6%9C%AF%E5%8D%9A%E6%96%87/2015/07/31/Android%E4%B8%AD%E7%9A%84%E8%8E%B7%E5%8F%96%E6%8E%A7%E4%BB%B6%E7%9F%A9%E9%98%B5getHitRect%E6%96%B9%E6%B3%95/


getHitRect的作用和用法

public void getHitRect(Rect outRect)这个方法用来找到控件占据的矩形区域的矩形坐标。 参数outRect表示控件占据的矩形区域。

测试代码如下,根据代码可以很直观的知道这个函数的用法:

public class MainActivity extends Activity {    private TextView textView = null;    private Button button = null;    Rect Trect = new Rect();    Rect Brect = new Rect();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        textView = (TextView) findViewById(R.id.tv01);        button = (Button) findViewById(R.id.btn);        button.setOnClickListener(new OnClickListener() {            public void onClick(View v) {                textView.getHitRect(Trect);                button.getHitRect(Brect);                Log.e("TAG", "---------TextView_left-------" + String.valueOf(Trect.left));                Log.e("TAG", "---------TextView_top-------" + String.valueOf(Trect.top));                Log.e("TAG", "---------TextView_right-------" + String.valueOf(Trect.right));                Log.e("TAG", "---------TextView_bottom-------" + String.valueOf(Trect.bottom));                Log.e("TAG", "---------Button_left-------" + String.valueOf(Brect.left));                Log.e("TAG", "---------Button_top-------" + String.valueOf(Brect.top));                Log.e("TAG", "---------Button_right-------" + String.valueOf(Brect.right));                Log.e("TAG", "---------Button_bottom-------" + String.valueOf(Brect.bottom));            }        });    }}     

查看log如下:

06-17 18:07:55.534: E/hailong(5797): ---------TextView_left-------28106-17 18:07:55.534: E/hailong(5797): ---------TextView_top-------47506-17 18:07:55.534: E/hailong(5797): ---------TextView_right-------43806-17 18:07:55.534: E/hailong(5797): ---------TextView_bottom-------51306-17 18:07:55.534: E/hailong(5797): ---------Button_left-------28106-17 18:07:55.534: E/hailong(5797): ---------Button_top-------51306-17 18:07:55.534: E/hailong(5797): ---------Button_right-------43906-17 18:07:55.534: E/hailong(5797): ---------Button_bottom-------609     

这样我们就可以知道控件的顶点坐标了。

可以用类似的方法判断是否点击到该控件上boolean isHit = Trect.contains((int)event.getX(), (int)event.getY());

注意:getHitRect作为获取控件所在的矩阵范围函数,我们平常调用时候如果是在控件的监听器里调用就没事, 但是如果主动的在onCreate 或者 onResume中,拿到的矩阵坐标全是0.因为getHitRect方法不能直接在onCreate中调用 ,原因是该控件还未在这个界面框架中得以测量布局,不知道到底是多少,所以我们要寻找一个时机去做这件事,两个方法:

1.运用该控件执行post(就把下面的那个parent当成你要获取getHitRect的方法)

final View parent = (View) delegate.getParent();parent.post( new Runnable() {    // Post in the parent's message queue to make sure the parent    // lays out its children before we call getHitRect()    public void run() {        final Rect r = new Rect();        delegate.getHitRect(r);        r.top -= 4;        r.bottom += 4;        parent.setTouchDelegate( new TouchDelegate( r , delegate));    }});     

2.自定义该控件,覆写onDraw,调用getHitRect.

扩大view点击范围

Android4.0设计规定的有效可触摸的UI元素标准是48dp,转化为一个物理尺寸约为9毫米。7~10毫米,这是一个用户手指能准确并且舒适触摸的区域。

如下图所示,你的UI元素可能小于48dp,图标仅有32dp,按钮仅有40dp,但是他们的实际可操作焦点区域最好都应达到48dp的大小。

为使小的UI区域获得良好的触摸交互,根据View的特性,目前碰到了两种情况:

1.如ImageView,设置其padding值,可触摸区域将向外扩展;

2.如Button,设置其padding值,可触摸区域不变,其内内容显示区域向内压缩;

情况1的控件,可直接设置其padding值达到目的,如 android:padding=”10dp”

情况2的控件,可使用TouchDelegate动态修改其触摸区域,达到扩大点击范围的效果.

这里大致说一下setTouchDelegate的作用:假设有两个View,分别是v1,v2,我们可以通过v1的setTouchDelegate(bounds, v2)来委派触摸事件, 其中bounds是一个Rect。v1中,落在这个范围的TouchEvent都会传给v2。

既然是这样,那我们可以通过设置某个view的parent的touchDelegate来达到扩大这个view触摸范围的目的。 关键是什么时候去执行parent.setTouchDelegate()方法呢?要设置这个委派,必须得知道当前view大小以及它在parent的位置。 而这些数据都是在onLayout才能确定(注:如果不是自定义View,只是在Activity中设置,请将这些操作置于onWindowFocusChanged()方法中)。

代码如下:

/**     * 扩大View的触摸和点击响应范围,最大不超过其父View范围     *     * @param view     * @param top     * @param bottom     * @param left     * @param right     */    public static void expandViewTouchDelegate(final View view, final int top,            final int bottom, final int left, final int right) {        ((View) view.getParent()).post(new Runnable() {            @Override            public void run() {                Rect bounds = new Rect();                view.setEnabled(true);                view.getHitRect(bounds);                bounds.top -= top;                bounds.bottom += bottom;                bounds.left -= left;                bounds.right += right;                TouchDelegate touchDelegate = new TouchDelegate(bounds, view);                if (View.class.isInstance(view.getParent())) {                    ((View) view.getParent()).setTouchDelegate(touchDelegate);                }            }        });    }       

采取此种方法的两点注意:

1、若View的自定义触摸范围超出Parent的大小,则超出的那部分无效。 2、一个Parent只能设置一个View的TouchDelegate,设置多个时只有最后设置的生效。

若需要恢复该View的触摸范围:

/**     * 还原View的触摸和点击响应范围,最小不小于View自身范围     *     * @param view     */    public static void restoreViewTouchDelegate(final View view) {        ((View) view.getParent()).post(new Runnable() {            @Override            public void run() {                Rect bounds = new Rect();                bounds.setEmpty();                TouchDelegate touchDelegate = new TouchDelegate(bounds, view);                if (View.class.isInstance(view.getParent())) {                    ((View) view.getParent()).setTouchDelegate(touchDelegate);                }            }        });    }     

使用TouchDelegate扩大View的触摸响应范围是一种比较灵活的方法,有时可与设置padding的方式结合使用。

注意:将此法应用在ListView的getView()中绘制每个ItemView时,则Delegate的设置将部分失效,原因是ListView的绘制较特殊,可能无法获取到部分还未绘制出的View的正确坐标。