在 childView.setScaleX()/setScaleY() 之后调整 ScrollView 视口的大小

Resize ScrollView viewport after childView.setScaleX()/setScaleY()

我的 TwoDScrollView 布局有问题。 TwoDScrollView 子视图缩放后,垂直和水平滚动范围保持不变

这是XML代码:

<com.fine.example.TwoDScrollView      
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scrolling"
    android:drawingCacheQuality="low"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/board"
        android:clipChildren="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawingCacheQuality="low"
        android:layout_marginTop="?android:attr/actionBarSize"
        android:layout_marginBottom="?android:attr/actionBarSize"
        android:paddingTop="@dimen/padmargsmedium"
        android:paddingBottom="?android:attr/actionBarSize"
        android:paddingLeft="@dimen/padmarg"
        android:paddingRight="@dimen/padmarg" >

        <RelativeLayout
            android:id="@+id/boardf"
            android:drawingCacheQuality="low"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

        </RelativeLayout>

    </RelativeLayout>

</com.fine.example.TwoDScrollView>

这就是我缩放 childView 的方式:

scale -= 0.25f;      // or scale += 0.25f;
board.setPivotX(0.5f/scale);
board.setPivotY(0.5f/scale);
board.setScaleX(1f/scale);
board.setScaleY(1f/scale);

实际上,我通过这样做设法修复了 "zoom in":

TwoDScrollView.LayoutParams params = (TwoDScrollView.LayoutParams) board.getLayoutParams();
params.width = (int) (xwidth/scale);
params.height = (int) (yheight/scale);
board.setLayoutParams(params);

但是对于 "zoom out" 相同的代码不起作用。子项的大小发生变化,但 ScrollView 不会更新其容器大小,滚动方式超过所需大小,同时在滚动视图与其缩放的子项之间显示空 space。

您可以在此处找到 TwoDScrollView 源代码(作者:Matt Clark):

https://web.archive.org/web/20121125032032/http://blog.gorges.us/2010/06/android-two-dimensional-scrollview/comment-page-1/#comments

我尝试过的事情:

我该如何解决这个问题?任何帮助将不胜感激!

最后我想出了一个 解决方案 缩小部分的脏 hax。不是最优的,但是嘿,它有效。

在TwoDScrollView.java中更改这三种方法:

@Override
protected float getBottomFadingEdgeStrength() {
    if (getChildCount() == 0) {
        return 0.0f;
    }
    final int length = getVerticalFadingEdgeLength();
    final int bottomEdge = getHeight() - getPaddingBottom();
    final int span = (int) (getChildAt(0).getBottom()/scale) - getScrollY() - bottomEdge;
    if (span < length) {
        return span / (float) length;
    }
    return 1.0f;
}

@Override
protected float getRightFadingEdgeStrength() {
    if (getChildCount() == 0) {
        return 0.0f;
    }
    final int length = getHorizontalFadingEdgeLength();
    final int rightEdge = getWidth() - getPaddingRight();
    final int span = (int) (getChildAt(0).getRight()/scale) - getScrollX() - rightEdge;
    if (span < length) {
        return span / (float) length;
    }
    return 1.0f;
}

@Override
public void computeScroll() {
    if (mScroller.computeScrollOffset()) {
        int oldX = getScrollX();
        int oldY = getScrollY();
        int x = mScroller.getCurrX();
        int y = mScroller.getCurrY();
        if (getChildCount() > 0) {
            View child = getChildAt(0);
            scrollTo(clamp(x, getWidth() - getPaddingRight() - getPaddingLeft(), (int) (child.getWidth() / scale)),
                    clamp(y, getHeight() + getPaddingBottom() - getPaddingTop(), (int) ((child.getHeight() + child.getPaddingBottom()) / scale)));
        } else {
            scrollTo(x, y);
        }
        if (oldX != getScrollX() || oldY != getScrollY()) {
            onScrollChanged(getScrollX(), getScrollY(), oldX, oldY);
        }
        postInvalidate();
    }
}

此外,请注意,如果有帮助,我正在使用 James McMurray 在 Gorges.blog 上建议的 measureChildWithMargins()

@Override
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
    final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

    int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED);
    int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.topMargin + lp.bottomMargin, MeasureSpec.UNSPECIFIED);

    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}

所以现在滚动视图父级将其边界限制为缩小的子级。它可以超出限制,但在发布时滚动视图布局会再次以适当的大小对齐。

如果有人有更好的解决方案,我很乐意给出答案。

还要感谢对我的问题投赞成票的神秘恩人:)