获取相对于父级ScrollView的视图坐标

6

之前,我有以下的 ScrollView 和布局。它的滚动到所选视图可见的代码可以正常工作。

<ScrollView>
    <LinearLayout>
        <Info View 1/>
        <Info View 2/>
        <Info View 3/>
    </LinearLayout>
</ScrollView>

private void initScrollView() {
    if (this.selectedInfoView == null) {
        // Nothing to scroll.
        return;
    }

    ScrollView scrollView = (ScrollView)this.getView().findViewById(R.id.scrollView);

    Rect rect = new Rect();
    Rect scrollViewRect = new Rect();
    selectedInfoView.getHitRect(rect);
    scrollView.getDrawingRect(scrollViewRect);
    int dy = rect.bottom - scrollViewRect.bottom;
    if (dy > 0) {
        scrollView.scrollBy(0, dy);
    }
}

注意,getHitRect将返回相对于上一级父级的坐标。所以,上面的代码可以正常工作。

然而,在稍微复杂的情况下,上述代码就不再适用。

<ScrollView>
    <LinearLayout 0>
        <TextView/>
        <LinearLayout 1>
            <Info View 1/>
            <Info View 2/>
            <Info View 3/>
        </LinearLayout>

        <TextView/>
        <LinearLayout 2>
            <Info View 4/>
            <Info View 5/>
            <Info View 6/>
        </LinearLayout>
    </LinearLayout>
</ScrollView>

在我的代码中,如果我遇到信息视图1-3,我需要考虑LinearLayout 0LinearLayout 1getHitRect。当涉及到信息视图4-6时,我需要考虑LinearLayout 0LinearLayout 2getHitRect

看起来很麻烦。有没有办法让我获取一个视图相对于最上面的ScrollView的坐标?


ScrollView 是否填满整个屏幕? - user
是的,就高度而言。它被用作滑动菜单。 - Cheok Yan Cheng
我不确定,但你是否看过http://developer.android.com/reference/android/view/View.html#getLocationInWindow%28int[]%29方法? - user
我尝试了,但不是100%有效。我将我的发现发布为答案之一。 - Cheok Yan Cheng
2个回答

9

这是目前可行的代码。虽然有点繁琐,但目前还能正常工作。我有几点观察。

private void initScrollView() {
    if (this.selectedInfoView == null) {
        // Nothing to scroll.
        return;
    }

    ScrollView scrollView = (ScrollView)this.getView().findViewById(R.id.scrollView);
    LinearLayout linearLayout = null;

    if (this.selectedInfo instanceof Info0) {
        linearLayout = (LinearLayout)this.getView().findViewById(R.id.linearLayout0);
    } else {
        assert(this.selectedInfo instanceof Info1);
        linearLayout = (LinearLayout)this.getView().findViewById(R.id.linearLayout1);
    }

    Rect rect = new Rect();
    Rect linearLayoutRect = new Rect();
    Rect scrollViewRect = new Rect();
    selectedInfoView.getHitRect(rect);
    linearLayout.getHitRect(linearLayoutRect);
    scrollView.getDrawingRect(scrollViewRect);

    // Get coordinate relative to linear layout. See the note below.
    int correct_expected_bottom_y = linearLayoutRect.top + rect.bottom;

    int dy = correct_expected_bottom_y  - scrollViewRect.bottom;
    if (dy > 0) {
        scrollView.scrollBy(0, dy);
    }
}

我用了getLocationInWindowgetLocationOnScreengetLocalVisibleRect进行测试,但它们都无法保证完全准确。
(x, y - width, height)
--------------------
|                  | (?, 120) <-- correct expected bottom y
|                  | (0, 146) <-- from getLocationInWindow/ getLocationOnScreen
|                  | (0, 0 - 360, 72) <-- from getLocalVisibleRect
--------------------
|                  | (?, 193) <-- correct expected bottom y
|                  | (0, 219) <-- from getLocationInWindow/ getLocationOnScreen
|                  | (0, 0 - 360, 72) <-- from getLocalVisibleRect
--------------------
|                  | (?, 266) <-- correct expected bottom y
|                  | (0, 292) <-- from getLocationInWindow/ getLocationOnScreen
|                  | (0, 0 - 360, 72) <-- from getLocalVisibleRect
--------------------
|                  | (?, 339) <-- correct expected bottom y
|                  | (0, 365) <-- from getLocationInWindow/ getLocationOnScreen
|                  | (0, 0 - 360, 72) <-- from getLocalVisibleRect
--------------------
|                  | (?, 485) <-- correct expected bottom y
| [not visible]    | (0, 511) <-- from getLocationInWindow/ getLocationOnScreen
|                  | (0, 413 - 360, 485) <-- from getLocalVisibleRect
--------------------

getLocationInWindow

获取此视图在窗口中的坐标位置,返回的值通常比预期的值多26个像素。例如,对于第一行,26 = 146 - 120。可能是由于 ActionBarStatusBar 的高度造成的。

getLocationOnScreen

getLocationInWindow 相同的行为。

getLocalVisibleRect

只有当该行完全不可见时,才能获得与预期值相同的值。不确定为什么。看最后一行,它具有与预期底部y值相同的底部y值(485)。


1
我猜窗口中的位置也对状态栏有影响,但你可以通过检查目标视图在窗口中的位置和ScrollView在窗口中的位置之间的差异来轻松地偏移接收到的位置,从而得出视图在ScrollView中的位置。 - user

2

不确定2013年是否可用,现在可以这样做:

val bounds = Rect()
childView.getDrawingRect(bounds) // now bounds has the visible drawing coordinates of the view
parentViewGroup.offsetDescendantRectToMyCoords(childView, bounds) // now bounds has the view's coordinates according to the parentViewGroup
< p > < code > parentViewGroup 是层次结构中 < code > childView 的任何级别的父级。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接