我正在开发我的第一个Android应用程序,经过一个良好的开端,我花了几天深度调试一个问题,现在似乎是API-23中View.requestRectangleOnScreen
的实现中的一个错误在此之前的许多层面。刚才,我发现在API-25中这个例程的实现发生了很大的变化。
问题是,关注放置在HorizontalScrollView内的EditText的请求可能导致HorizontalScrollView滚动离开请求焦点的字段。 在我的例子中,它是一个带有居中文本的EditText,然后放置在1048576像素的中心,向右滚动大约五十万个像素,使文本居中和可见(这部分完全正常!)但是这个偏移量50万像素传播到父链上,使HorizontalScrollView移动到最右边,远离输入字段。
我已将其跟踪到View.requestRectangleOnScreen例程,该例程在API-23源中如下:
public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) {
if (mParent == null) {
return false;
}
View child = this;
RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF();
position.set(rectangle);
ViewParent parent = mParent;
boolean scrolled = false;
while (parent != null) {
rectangle.set((int) position.left, (int) position.top,
(int) position.right, (int) position.bottom);
scrolled |= parent.requestChildRectangleOnScreen(child,
rectangle, immediate);
if (!child.hasIdentityMatrix()) {
child.getMatrix().mapRect(position);
}
position.offset(child.mLeft, child.mTop);
if (!(parent instanceof View)) {
break;
}
View parentView = (View) parent;
position.offset(-parentView.getScrollX(), -parentView.getScrollY());
child = parentView;
parent = child.getParent();
}
return scrolled;
}
这个想法是通过在每个包含View的屏幕上滚动它来使rectangle
可见,从叶级开始并将请求传递给父母链。最初的rectangle
在子坐标系中给出,当然我们在父母的链条上工作时必须进行调整。这是通过声明
position.offset(-parentView.getScrollX(), -parentView.getScrollY());
接近上面代码的结尾。
我发现,这是错误的,因为我们正在使用与父坐标相关的滚动X / Y值转换子坐标中给出的position
。使用孩子的滚动X / Y代替我解决了我的问题,但是不可能完美地覆盖这个例程,因为它依赖于私有成员变量。具体来说,我发现无法模仿mAttachInfo
。
现在,进一步挖掘,我发现API-25中此例程的代码已经显着改变,并且(恕我直言)正确地改为:
public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) {
if (mParent == null) {
return false;
}
View child = this;
RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF();
position.set(rectangle);
ViewParent parent = mParent;
boolean scrolled = false;
while (parent != null) {
rectangle.set((int) position.left, (int) position.top,
(int) position.right, (int) position.bottom);
scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate);
if (!(parent instanceof View)) {
break;
}
// move it from child's content coordinate space to parent's content coordinate space
position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY());
child = (View) parent;
parent = child.getParent();
}
return scrolled;
}
最重要的变化是行
position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY());
现在使用子值进行滚动X / Y调整。
现在,我有两个问题。
首先,您是否同意我上面的观察结果?
其次,如何在特定情况下实现可在API-23和API-25上使用的应用程序?
我目前的想法是对EditText进行子类并覆盖requestRectangleOnScreen
方法,这样当API为25及以上时,它只调用超类方法,当API低于25时,我基本上做了一个完全覆盖使用API-25代码中的代码,但在mAttachInfo
部分错过了。