DEVLOG 10.9 FrameLayout & addView

问题1:在这段代码中 为什么不能将addView放到最底下?
如果将最后一行addView放到最底下,会出现NPE,表示layoutParams不能从textView中获取到。所以这个问题就转化成两个子问题:
原本的View中LayoutParams都是空的吗?
addView是如何处理LayoutParams的呢?

1, View中的LayoutParams都是空的吗?

从文档中我们可以看出View#getLayoutParams方法会在两种情况下返回空:
- 如果当前的子View没有attach到ViewGroup
- 如果setLayoutParams没有正常生效
在View中,只有View#setLayoutParams将外界传入的View绑定到View的全局参数LayoutParams:
在绑定成功之后,会重新请求布局,所以ViewGroup会考虑更新之后的LayoutParams。
如果不使用setLayoutParams,View中的LayoutParams为空。(当然,如果通过解析xml的方式也算设置了LayoutParams)
所以,我们可以通过addView将子View添加到(attach)到ViewGroup,所以为了避免下面出现异常,我们需要先进行addView。

2, addView对于LayoutParams的处理
根据addView的重载方法来看,addView也有不接收LayoutParams的重载方法:

不过这个方法也会调用View#getLayoutParams。如果是直接指定宽高的addView重载,会生成默认的LayoutParams:
综上所述,上面的代码中没有必要使用LinearLayout.Params,因为GridLayout并没有重载addView,可以直接使用LayoutParams,不需要考虑子类。当然直接指定宽高的话也可以,代码可以这样写:

Scroller View#scrollTo View#scrollBy View#computeScroll
农夫三拳:Scroller#startScroll View#computeScroll postInvalidate
拿我在这篇文章画的这个图为例:

Scroller需要调用startScroll作为滑动开始信号,View中需要实现computeScroll计算是否完成滑动,然后调用自身scrollTo滑动到确定的位置,最后调用postInvalidate更新。
用invalidate也行,postInvalidate 和 invalidate的区别在于invalidate会立刻重绘,postInvalidate可以从非UI线程,发送一条消息到UI线程的Handler,再重绘View。