View[2] left、top、right、bottom

来源:互联网 发布:.club域名 编辑:程序博客网 时间:2024/06/01 16:32

【参考链接】

《开发艺术探索》P190

 

View的长宽及其在父ViewGroup中的位置


什么时候才能获取的到?

从《ActivityWindowView执行流程概述[2]》中可知,只有在View执行了它自身的layout()及其中的setFrame()以后,才能确定它的大小及在父ViewGroup中的位置。

 

如何获取?

View提供了getLeft()getTop()getRight()getBottom()方法来获取自身的四个点相对于父ViewGroup的距离,通过他们可以知道长宽和位置。

Log.e("shadowfaxghh","top="+tv.getTop()+" left="+tv.getLeft()+" right="+tv.getRight()+" bottom="+tv.getBottom());

 

如何改变?

严格来说,是无法自由改变View在其父ViewGroup中的位置的。因为其需要服从父ViewGroup的布局规则的约束。

requestLayout()

可以修改View的布局参数LayoutParams,然后使用requestLayout()使其生效。

setLayoutParams()、属性动画等,因其内部也是在调用requestLayout(),所以也可以实现功能。

其执行流程见《requestLayout()invalidate()

       FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)tv.getLayoutParams();
       
layoutParams.width=100;
       
layoutParams.height=100;
       
layoutParams.leftMargin=100;
       
layoutParams.topMargin=100;
       
tv.requestLayout();
//       tv.setLayoutParams(layoutParams);


 

关于layout()方法

也可以直接调用layout()方法来改变View在其父ViewGroup中的大小和位置

其执行流程是,会进行layout(),然后再执行一次performTraversals,但是此时mLayoutRequested=false,所以此次performTraversals并不会执行measure()layout(),只会执行draw()

因此,它有个优点是,可以避开父ViewGroup的布局约束,自由放置位置。但是也有个缺点是,因为缺少了measure(),所以如果draw()时需要用到measure()时产生的辅助数据,则会导致draw()效果异常。

所以可以用它来改变View的位置,但尽量不要用来改变View的大小。

tv.layout(100,100,200,200);

 

绘制异常:

只绘制出了一行,正常应该同上面一样绘制出两行,这是因为在measure()时会计算好绘制行数(查看源码可知是保存在一个Layout类型的成员变量中),这里直接使用旧的绘制行数,所以绘制异常。

避开布局约束、自由放置位置:

3TextView是放在一个LinearLayout中,改变中间这个TextView,并没有影响到下面的TextView

 

一些其他问题

前面讲了,在正常流程下,只有在setFrame()以后才能确认View的长宽和位置

不过在《开发艺术探索》中,也讲了几种方法用于在不同时刻获取某个View的长宽和位置,但是除了ViewTreeObserver,个人感觉都很纠结。仅在此记录一下,遇到实际情况再实际选择使用

View.measure()

Activity.onWindowFocusChanged()

ViewTreeObserver

View.post()

 

 

 

后续更新

从Android 3.0/API 11开始,Android又给View增加了一些Property,如translation、rotation、scale等。

通过修改他们也能够改变View的长宽及其在父ViewGroup中的位置

但是却没有改变left\top\right\bottom,也没有引发重新onDraw()

所以现在位置已经不能单纯用left\top\right\bottom来表示了,只能算是View布局完成以后的初始位置。

 

原创粉丝点击