View.transform 与 View.scroll 与 Canvas.transform
View.transform 代表了:
android.view.View.setTranslationX::float:
android.view.View.setTranslationY::float:
android.view.View.setTranslationZ::float:
android.view.View.setRotation::float:
android.view.View.setRotationY::float:
android.view.View.setRotationX::float:
android.view.View.setScaleX::float:
android.view.View.setScaleY::float:
这些对视图的变形操作,Canvas.transform 也能代表这么多变形操作。
View.transform 与 View.scroll 的区别与联系:
- View.transform 是将视图本身移动,View.scroll 则是视图本身不动,所有的子视图移动
- 在感觉上 View.transform 与 View.scroll 的移动方向是反的,如View.setTranslationX(100)是视图本身向右移动100,View.setScrollX(100) 是所有子视图向左移动100。
- View.transform 的值存在native层,View.scroll的值存在java层。
- View.transform 不影响视图本身的 layout,View.scroll 会在感受上影响子视图的 layout 位置。
- View.transform 与 View.scroll 的一个相同点是它们都会影响 MotionEvent,也就是所有的 MotionEvent 在分发的时候都要经过 scroll 与 transform 这两种变形移位,因此视图接收点击事件的范围会跟着视图的变形一起变化。有函数为证:
android.view.ViewGroup.transformPointToViewLocal::float,View:src
/**
* @hide
*/
public void transformPointToViewLocal(float[] point, View child) {
point[0] += mScrollX - child.mLeft;
point[1] += mScrollY - child.mTop;
if (!child.hasIdentityMatrix()) {
child.getInverseMatrix().mapPoints(point);
}
}
这里的 child.getInverseMatrix() 获得的 Matrix 就是 记录View.transform变形的矩阵 的逆矩阵。这个矩阵也是从 native 层取出来的。
View.transform 与 Canvas.transform 的区别与联系:
- View.transform 会影响点击事件,意思是视图接收点击事件的范围会跟着视图的变形一起变化,Canvas.transform 不会,因此对 Canvas 变形前都会先使用 save 函数保存原来的状态,等绘制完了再使用 restore 函数恢复原来的状态,以免让你有视图接收不到点击事件的感觉(这种感觉是因为视图的事件接收范围与显示范围不一致造成的)。
- 这两种变形都不会影响 layout,View.transform 会影响点击事件,让你感觉视图不仅是显示发生了变化,而且布局也变化了,但其实没有。
Canvas.transform 与 View.transform 与 View.scroll 的联系:
View.transform 与 View.scroll 的效果都是通过 Canvas.transform 来实现的,具体实现过程看函数android.view.View.draw::Canvas,ViewGroup,long:。这也解释了 View.transform 为什么没有影响布局。
那 View.scroll 为什么会影响子视图的布局呢,其实本质上它也没有让子视图的布局移位,只是它绘制子视图(dispatchDraw)之前将整个 Canvas 向前移位了,子视图绘制结束后它又使用函数 restore 将 Canvas 恢复了(向后移位),因此有了子视图的布局被整体后移的感觉。
关于布局多说一句
存放视图布局的数据结构只有mLeft,mRight,mTop,mBottome 这四个值,因此它不可能给视图带来丰富的变形功能,因此视图的形变没有通过 layout 来实现(通过 layout 顶多可以实现视图平移,但为了统一,平移的功能也没有用 layout 实现),而是使用 Canvas.transform 来实现,也因此 View.transform 绝不会影响 layout 。