如何在Android上实现NestedScrolling?
使用support-v4库22.1.0 android支持嵌套滚动(pre android 5.0)。 不幸的是,这个function没有真正的logging。 有两个接口( NestedScrollingParent
和NestedScrollingChild
)以及两个辅助委托类( NestedScrollingChildHelper
和NestedScrollingParentHelper
)。
有没有人在Android上使用NestedScrolling?
我试图设置一个小例子,在那里我使用NestedScrolling实现了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; } }); } }
所以,标题视图将部分滚动,40像素将保持可见,因为我将嵌套的子滚动视图的高度设置为parentScroll.getHeight() - 40
。 好的,在运行时设置高度,滚动父滚动视图就像预期一样工作(滚动标题,40像素保持可见,然后子滚动视图填充标题下方的屏幕的其余部分)。
我期望“NestedScrolling”意味着我可以在屏幕上的任何地方做一个滚动手势(触摸由父滚动视图捕获的事件),如果父滚动视图已经到达结尾,则嵌套的子滚动视图开始滚动。 但是,似乎并非如此(既不是简单的滚动手势,也不是为了打手势)。
触摸事件总是由嵌套的子滚动视图处理,如果触摸事件在其边界开始,否则通过父滚动视图。
这是“嵌套滚动”的预期行为还是有一个选项来改变这种行为?
我也尝试用NestedRecyclerView
replace嵌套的子滚动视图。 我subclassed 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
根本不滚动。 所有触摸事件都由父滚动视图捕获。
我花了相当多的时间在这个刚刚通过android代码试图找出NestedScrollView中发生了什么。 以下应该工作。
public abstract class ParentOfNestedScrollView extends NestedScrollView{ public ParentOfNestedScrollView(Context context, AttributeSet attrs) { super(context, attrs); } /* Have this return the range you want to scroll to until the footer starts scrolling I have it as headerCard.getHeight() on most implementations */ protected abstract int getScrollRange(); /* This has the parent do all the scrolling that happens until you are ready for the child to scroll. */ @Override public void onNestedPreScroll(View target, int dx, int dy, int[] consumed){ if (dy > 0 && getScrollY() < getScrollRange()) { int oldScrollY = getScrollY(); scrollBy(0, dy); consumed[1] = getScrollY() - oldScrollY; } } /* Sometimes the parent scroll intercepts the event when you don't want it to. This prevents this from ever happening. */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return false; } }
我的一些代码是从这个问题借来的。 从这里我只需要扩展这个类。 我的xml有一个孩子作为NestedScrollView作为一个孩子和父母这样做。 这不是我想要的,但这是一个正在进行的工作。