在 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):
我尝试过的事情:
将 TwoDScrollView 替换为 ScrollView 并设置 fillViewPort="true",但同样发生。
在两种布局和所有可能的组合中将 layout_width 和 layout_height 更改为 WRAP_CONTENT 或 MATCH_PARENT。
与 invalidate() 和 requestLayout() 相同。
将可见性设置为 GONE,然后设置为 VISIBLE,如此处解释:ScrollView does not resize directly after child changes.
我什至尝试在这些 TwoDScrollView 方法中强制缩放:computeVerticalScrollRange、computeHorizontalScrollRange、measureChild、measureChildWithMargins 和 computeScroll,但没有结果。
搜索Whosebug:有一些问题和我一样,但当有答案时,遗憾的是它对我不起作用。
我该如何解决这个问题?任何帮助将不胜感激!
最后我想出了一个 解决方案 缩小部分的脏 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);
}
所以现在滚动视图父级将其边界限制为缩小的子级。它可以超出限制,但在发布时滚动视图布局会再次以适当的大小对齐。
如果有人有更好的解决方案,我很乐意给出答案。
还要感谢对我的问题投赞成票的神秘恩人:)
我的 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):
我尝试过的事情:
将 TwoDScrollView 替换为 ScrollView 并设置 fillViewPort="true",但同样发生。
在两种布局和所有可能的组合中将 layout_width 和 layout_height 更改为 WRAP_CONTENT 或 MATCH_PARENT。
与 invalidate() 和 requestLayout() 相同。
将可见性设置为 GONE,然后设置为 VISIBLE,如此处解释:ScrollView does not resize directly after child changes.
我什至尝试在这些 TwoDScrollView 方法中强制缩放:computeVerticalScrollRange、computeHorizontalScrollRange、measureChild、measureChildWithMargins 和 computeScroll,但没有结果。
搜索Whosebug:有一些问题和我一样,但当有答案时,遗憾的是它对我不起作用。
我该如何解决这个问题?任何帮助将不胜感激!
最后我想出了一个 解决方案 缩小部分的脏 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);
}
所以现在滚动视图父级将其边界限制为缩小的子级。它可以超出限制,但在发布时滚动视图布局会再次以适当的大小对齐。
如果有人有更好的解决方案,我很乐意给出答案。
还要感谢对我的问题投赞成票的神秘恩人:)