View[2] left、top、right、bottom
【参考链接】
《开发艺术探索》P190
View的长宽及其在父ViewGroup中的位置
什么时候才能获取的到?
从《Activity、Window、View执行流程概述[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类型的成员变量中),这里直接使用旧的绘制行数,所以绘制异常。
|
|
避开布局约束、自由放置位置:
3个TextView是放在一个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布局完成以后的初始位置。