HorizontalScrollView在重新layout时,有时候会自动滑动到其他位置,这是由于他的后代view获取到焦点导致的,来让我们从代码层面看清这个问题:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childWidth = 0;
int childMargins = 0;
if (getChildCount() > 0) {
childWidth = getChildAt(0).getMeasuredWidth();
LayoutParams childParams = (LayoutParams) getChildAt(0).getLayoutParams();
childMargins = childParams.leftMargin + childParams.rightMargin;
}
final int available = r - l - getPaddingLeftWithForeground() -
getPaddingRightWithForeground() - childMargins;
final boolean forceLeftGravity = (childWidth > available);
layoutChildren(l, t, r, b, forceLeftGravity);
mIsLayoutDirty = false;
// Give a child focus if it needs it
//就是在这一行,scrollView自动滑动到那个有焦点的view的位置
if (mChildToScrollTo != null && isViewDescendantOf(mChildToScrollTo, this)) {
scrollToChild(mChildToScrollTo);
}
mChildToScrollTo = null;
if (!isLaidOut()) {
final int scrollRange = Math.max(0,
childWidth - (r - l - mPaddingLeft - mPaddingRight));
if (mSavedState != null) {
mScrollX = isLayoutRtl()
? scrollRange - mSavedState.scrollOffsetFromStart
: mSavedState.scrollOffsetFromStart;
mSavedState = null;
} else {
if (isLayoutRtl()) {
mScrollX = scrollRange - mScrollX;
} // mScrollX default value is "0" for LTR
}
// Don't forget to clamp
if (mScrollX > scrollRange) {
mScrollX = scrollRange;
} else if (mScrollX < 0) {
mScrollX = 0;
}
}
// Calling this with the present values causes it to re-claim them
scrollTo(mScrollX, mScrollY);
}
@Override
public void requestChildFocus(View child, View focused) {
if (!mIsLayoutDirty) {
scrollToChild(focused);
} else {
// The child may not be laid out yet, we can't compute the scroll yet
mChildToScrollTo = focused;
}
super.requestChildFocus(child, focused);
}
覆写父类方法onLayout,就可以解决这个问题
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int tempScrollX = getScrollX();
super.onLayout(changed, l, t, r, b);
final int scrollX = getScrollX();
if (tempScrollX != scrollX) {
this.scrollTo(tempScrollX, 0);
}
}