为什么说scroll方法移动的是他的孩子?
在思考mScrollX,mScrollY
这两个参数对View
的绘制会产生什么样的影响的时候,我看了这么个代码:
1 | class View{ |
看方法名字很容易知道这是绘制背景的。但是我们在实战中会发现调用TextView.scrollBy(10f,10f)
的时候,只有TextView
的内容移动了位置,但是我们给TextView
设置的背景并没有产生移动。带着这个疑问你看源码,在调用background.draw(canvas)
之前不是调用了canvas.translate(mScrollX, mScrollX)
对画布进行了移动吗??????为啥我们的背景确并没有进行移动!!!!!!!!!
哈哈,你既然看到了这里,想必你也产生了和我同样的问题。现在就带着问题来看源码,为什么我们的背景没有进行移动。
首先对整个View
的绘制流程进行源码解析:
ViewRootImpl触发draw(canvas)方法。
draw(canvas)分四部走。
- drawBackground(canvas) : 绘制背景
- onDraw(canvas) : 绘制自己
- dispatchDraw(canvas) : 绘制孩子
- 绘制bar(忽略不管)
这里我先模拟这么个层级:
1 | <Framelayout> |
我来分析下:首先ViewRootImpl
调用了FrameLayout
的draw(canvas)
方法。然后FrameLayout
调用了drawBackground
绘制了FrameLayout
的背景。然后调用了FrameLayout
的onDraw(canvas)
方法。我们知道自定义ViewGroup
的时候很少几乎不会重写onDraw(canvas)
方法。只有自定义View
的时候才会重写。然后接着调用了FrameLayout
的dispatchDraw(canvas)
方法。在这个里面会遍历所有的孩子调用child.draw(canvas, this, drawingTime)
。可以看到到了这里就走进了子孩,在这里也就是ImageView
的draw(canvas, this, drawingTime)
方法。然后在这个draw(canvas, this, drawingTime)
方法里面会调用孩子的draw(canvas)
方法。
注意重点来了:我们知道绘制背景的代码是在
draw(canvas)
这个方法里调用的。现在你想下在绘制背景前会调用canvas.translate(mScrollX, mScrollX)
但是最终的现象是调用了这个方法,我们的背景并没有偏移。既然没有偏移,我们是不是可以猜想我们的画布在调用偏移前已经提前偏移过了一次,这次绘制背景前的偏移其实和之之前的偏移只是进行了一个抵消操作,所以我们的背景没有移动。哈哈,其实就是这么个过程,我们刚才分析了ViewGroup
的dispatchDraw(canvas)
方法。他调用了child.draw(canvas, this, drawingTime)
也就是这个方法draw(canvas, this, drawingTime)
先于背景的偏移前进行了一次偏移。
1 | boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { |
看在倒数第四行调用了canvas.translate()
对视图已经进行了偏移。
到此为什么我们的背景不会移动已经讲清楚了。