Dzięki obsłudze biblioteki v4 22.1.0 android obsługuje zagnieżdżone przewijanie (pre Android 5.0). Niestety ta funkcja nie jest tak naprawdę udokumentowana. Istnieją dwa interfejsy (NestedScrollingParent
i NestedScrollingChild
) oraz dwie klasy delegatów pomocniczych (NestedScrollingChildHelper
i NestedScrollingParentHelper
).Jak zaimplementować NestedScrolling na Androida?
Czy ktoś pracował z NestedScrolling na Androida?
Próbowałem ustawić mały przykład, gdzie używam NestedScrollView, który implementuje zarówno NestedScrollingParent
i NestedScrollingChild
.
Mój układ wygląda następująco:
<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>
Chcę wyświetlić header view
i inny NestedScrollView
(id = dziecko) w NestedScrollView
(id = rodzic).
Chodziło o to, aby dostosować wysokość widoku przewijania dziecka w czasie wykonywania przy użyciu 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;
}
});
}
}
więc widok nagłówka będą przewijane dala częściowo, 40 pikseli pozostaną widoczne odkąd ustaw wysokość zagnieżdżonego przewijania podrzędnego do parentScroll.getHeight() - 40
. W porządku, ustawienie wysokości w czasie wykonywania i przewijanie nadrzędnego widoku przewijania działa tak, jak oczekiwano (nagłówek przewija się, 40 pikseli pozostaje widocznych, a następnie przewijany przez dziecko wypełnia resztę ekranu poniżej nagłówka).
Spodziewam się, że "NestedScrolling" oznacza, że mogę wykonać gest przewijania w dowolnym miejscu na ekranie (zdarzenie dotykowe przechwycone przez nadrzędny widok przewijania) i jeśli widok przewijania nadrzędnego osiągnął koniec, zagnieżdżony przewijany widok potomny zaczyna przewijać . Jednak wydaje się, że tak nie jest (ani w przypadku prostych gestów przewijania, ani gestów rzucania).
Zdarzenie dotykowe jest zawsze obsługiwane przez zagnieżdżone przewijanie podrzędne, jeśli zdarzenie dotykowe zaczyna się w jego granicach, w przeciwnym razie przez nadrzędny widok przewijania.
Czy jest to oczekiwane zachowanie "zagnieżdżonego przewijania" lub czy istnieje możliwość zmiany tego zachowania?
Próbowałem również zastąpić zagnieżdżony widok przewijania podrzędnego za pomocą NestedRecyclerView
. I podklasy RecyclerView
i wdrożone NestedScrollingChild
gdzie mogę przekazać wszystkie metody 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);
}
}
ale NestedRecyclerView
nie przewiń w ogóle. Wszystkie zdarzenia dotyku są przechwytywane przez nadrzędny widok przewijania.
Mam ten sam problem i myślę, że ten widget powinien zostać ulepszony, aby umożliwić rodzicowi niepotrzebne przewinięcie do jego dziecka. –
Myślę, że sprawienie, aby widok recyklera był zagnieżdżony w trybie przewijaniaScrollingChild, nie jest tak łatwy, ponieważ używa On programu LayoutManager do przewijania i pozycjonowania jego elementu. Dlatego tylko implementacja NestedScrollingChild z NestedScrollingChildHelper nie będzie działać, ponieważ funkcje te nie są wywoływane podczas przewijania. –
Nie jestem pewien. Przypuszczam, że NestedScrollingParent/NestedScrollingChild służy do przekazywania zdarzenia dotyku. Mam nadzieję, że 'NestedScrollingChild' wewnętrznie to robi, nie widzę żadnego powodu, dla którego powinien on działać dla' ScrollView', ale nie dla 'RecyclerView' ...' LayoutManager' nie powinien być problemem ... – sockeqwe