实践是检验真理的唯一标准
问题缘由:自定义View开发的小伙伴,肯定会遇到。代码中onCreate() 方法中 ,直接调用view.layout()想要移动控件位置的时候,发现效果并没有达到预期的(控件一点都没有移动,尴尬),然而通过Value动画调用该方法的时候,是起作用的。why?why?。
ValueAnimator animator=ValueAnimator.ofInt(0,400);
animator.setDuration(3000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
iv.layout(iv.getLeft(),value,iv.getRight(),value+iv.getHeight());
}
});
animator.start();
开始办案:value动画,只是起了一个返回数值的作用,控件位置移动最终还是通过 layout 方法。因此,能接受的解释就是,layout 的起作用肯定是在某一个时刻执行的(确定的是,oncreate()执行的时候,它肯定无效)。
验证:oncreate() 中,延时3秒执行 view.layout() ,果然是起作用的。
iv.postDelayed(new Runnable() {
@Override
public void run() {
iv.layout(0,0,iv.getWidth(),iv.getHeight());
}
},3000);
因此,onlayout能否有效,只是一个时机的问题。通过实验:当activity的布局,完全布局成功的以后,layout 才会有效。onGlobalLayout()方法,执行了3次,在最后一次执行完以后,才有效果。
final int[] i = {0};
iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Log.i("LHT","onGlobalLayout "+i[0]);
if(i[0] ==2){
iv.layout(0,0,iv.getWidth(),iv.getHeight());
}
i[0]++;
Log.i("LHT","left "+iv.getLeft());
}
});
测试中,onGlobalLayout() 一共回调了3次,当在第三次 以后,onlayout()起作用。从而延深到 getTop() 等方法,在onCreate() ,获取到的值为0,这也是个时机的问题。
解决方法,可以view.post() run方法中获取,或者 和上面一样 ,在 onGlobalyout() 方法中获取。
offsetLeftAndRight(); offsetTopAndBottom(); 系统封装api 可以替代 layout()