在支持库 22.1.0 上,安卓系统已经支持嵌套滚动(android 5.0之前)。不幸的是,这个特性并没有得到很好的记录。它包含两个接口(NestedScrollingParent
和NestedScrollingChild
)以及两个辅助代理类(NestedScrollingChildHelper
和NestedScrollingParentHelper
)。
有人在安卓上使用过嵌套滚动吗?
我尝试设置一个小例子,在其中使用了NestedScrollView,它同时实现了NestedScrollingParent
和NestedScrollingChild
接口。
我的布局看起来像这样:
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:id="@+id/header"
android:layout_width="match_parent" android:layout_height="100dp"
android:background="#AF1233"/>
<android.support.v4.widget.NestedScrollView
android:id="@+id/child"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#12AF33"
android:text="@string/long_text"/>
</FrameLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
我想在一个NestedScrollView
(id = parent)中显示一个header view
和另一个NestedScrollView
(id = child)。
我的想法是使用一个OnPredrawListener
来动态调整子滚动视图的高度:
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final NestedScrollView parentScroll = (NestedScrollView) findViewById(R.id.parent);
final NestedScrollView nestedScroll = (NestedScrollView) findViewById(R.id.child);
parentScroll.setNestedScrollingEnabled(false);
final View header = findViewById(R.id.header);
parentScroll.getViewTreeObserver()
.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override public boolean onPreDraw() {
if (parentScroll.getHeight() > 0) {
parentScroll.getViewTreeObserver().removeOnPreDrawListener(this);
nestedScroll.getLayoutParams().height = parentScroll.getHeight() - 40;
nestedScroll.setLayoutParams(nestedScroll.getLayoutParams());
nestedScroll.invalidate();
return false;
}
return true;
}
});
}
}
因此,标题视图将被部分滚动,因为我将嵌套子滚动视图的高度设置为parentScroll.getHeight() - 40
,其中40个像素会保持可见。
好的,运行时设置高度并滚动父滚动视图按预期工作(标题滚出,剩下的40个像素可见,然后子滚动视图填充标题以下屏幕的其余部分)。我希望“嵌套滚动”意味着我可以在屏幕上的任何位置进行滚动手势(由父滚动视图捕获的触摸事件),如果父滚动视图已达到末尾,则嵌套子滚动视图开始滚动。 但是似乎并非如此(对于简单的滚动手势或快速滑动手势都不是如此)。
如果触摸事件在嵌套子滚动视图的边界内开始,则始终由嵌套子滚动视图处理触摸事件,否则由父滚动视图处理。
这是否是“嵌套滚动”的预期行为,还是有更改该行为的选项?
我还尝试用
NestedRecyclerView
替换了嵌套子滚动视图。 我子类化RecyclerView
并实现NestedScrollingChild
,其中我将所有方法委托给NestedScrollingChildHelper
:public class NestedRecyclerView extends RecyclerView implements NestedScrollingChild {
private final NestedScrollingChildHelper scrollingChildHelper =
new NestedScrollingChildHelper(this);
public void setNestedScrollingEnabled(boolean enabled) {
scrollingChildHelper.setNestedScrollingEnabled(enabled);
}
public boolean isNestedScrollingEnabled() {
return scrollingChildHelper.isNestedScrollingEnabled();
}
public boolean startNestedScroll(int axes) {
return scrollingChildHelper.startNestedScroll(axes);
}
public void stopNestedScroll() {
scrollingChildHelper.stopNestedScroll();
}
public boolean hasNestedScrollingParent() {
return scrollingChildHelper.hasNestedScrollingParent();
}
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
int dyUnconsumed, int[] offsetInWindow) {
return scrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed,
dyUnconsumed, offsetInWindow);
}
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
return scrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return scrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return scrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
}
但是NestedRecyclerView
根本无法滚动。 所有触摸事件都被父滚动视图捕获。
onTouchEvent
方法中,没有调用那些NestedScrollingChild
方法,而NestedScrollView
有。 - Morty Choi