for (int i = childrenCount - 1; i >= 0; i--) {
...............
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
ev.setTargetAccessibilityFocus(false);
continue;
}
...............
}
/**
* Returns true if a child view contains the specified point when transformed
* into its coordinate space.
* Child must not be null.
* @hide
*/
protected boolean isTransformedTouchPointInView(float x, float y, View child,
PointF outLocalPoint) {
final float[] point = getTempPoint();
point[0] = x;
point[1] = y;
transformPointToViewLocal(point, child);
//判断坐标在不在view中
final boolean isInView = child.pointInView(point[0], point[1]);
//outLocalpoint在拖拽事件中用到;
if (isInView && outLocalPoint != null) {
outLocalPoint.set(point[0], point[1]);
}
return isInView;
}
/**
* @hide
*/
//转换成view坐标系的坐标;
public void transformPointToViewLocal(float[] point, View child) {
//这个是把触摸点转换为相对于孩子左上角的坐标;
point[0] += mScrollX - child.mLeft;
point[1] += mScrollY - child.mTop;
if (!child.hasIdentityMatrix()) {
//图像的内部进行了变换:如平移,旋转等; point位置应该是view经过matrix映射后的点,因此要用逆矩阵来映射;点击区域即使在view内部,point计算出来
//后,也可能不在view内部;
child.getInverseMatrix().mapPoints(point);
}
}
/** * Determines whether the given point, in local coordinates is inside the view. */ /*package*/ final boolean pointInView(float localX, float localY) { return localX >= 0 && localX < (mRight - mLeft) && localY >= 0 && localY < (mBottom - mTop); }
映射坐标的方法:
顺时针旋转:
图为 (x0,y0) 顺时针旋转变换为(x1,y1);
x0 = r*cos α;
y0 = r*sin α;
x1 = r*cos(α+θ) = x0/cos α *cos α*cosθ -y0/sin α*sin α*sin θ) =x0*cosθ-y0*sinθ ;
y1 = r*sin(α+θ) ;
转换矩阵
x1 cos θ -sin θ 0 x0
y1 = sin θ cos θ 0 * y0
1 0 0 1 1
;
平移:
x1 1 0 Δx x0
y1 = 0 1 Δy * y0
1 0 0 1 1
缩放:
x1 a 0 0 x0
y1 = 0 b 0 * y0
1 0 0 1 1
设: 图形变换顺序为 x1,x2,x3..xn; 对应变换 矩阵为T1,T2,....Tn; 则矩阵相乘的顺序为:Tn*Tn-1*...T1;
android中Matrix提供的变换方法;
/**
* Preconcats the matrix with the specified rotation.
* M' = M * R(degrees, px, py)
*/
public boolean preRotate(float degrees, float px, float py) {
native_preRotate(native_instance, degrees, px, py);
return true;
}
通过上面可以看出: scrollTo方法设置滚动过程不影响触摸事件分发; 因为每一次当前View滚动后:内容的触摸事件都会通过 point[0] += mScrollX - child.mLeft;
把point相对于View坐标系,转化为相对于View内容坐标系坐标;因此不影响滚动;
另外ScrollTo也只是走绘制过程;