В библиотеке support-v4 22.1.0 андроид поддерживает вложенную прокрутку (pre android 5.0). К сожалению, эта функция не документирована. Существует два интерфейса (NestedScrollingParent
и NestedScrollingChild
), а также два класса делегатов-помощников (NestedScrollingChildHelper
и NestedScrollingParentHelper
).
Кто-нибудь работал с NestedScrolling на Android?
Я попытался настроить небольшой пример, где я использую 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>
Я хочу показать header view
и еще один NestedScrollView
(id = child) в NestedScrollView
(id = parent).
Идея заключалась в том, чтобы отрегулировать высоту детского прокрутки во время выполнения с помощью 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
. Я подклассифицировал 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
не прокручивается вообще. Все события касания захватываются представлением родительской прокрутки.