Modyfikatory przewijania
Modyfikatory
verticalScroll
i
horizontalScroll
to najprostszy sposób, aby umożliwić użytkownikowi przewijanie elementu, gdy granice jego zawartości są większe niż maksymalne ograniczenia rozmiaru. W przypadku modyfikatorów verticalScroll
i horizontalScroll
nie musisz tłumaczyć ani przesuwać treści.
@Composable private fun ScrollBoxes() { Column( modifier = Modifier .background(Color.LightGray) .size(100.dp) .verticalScroll(rememberScrollState()) ) { repeat(10) { Text("Item $it", modifier = Modifier.padding(2.dp)) } } }
Element ScrollState
umożliwia zmianę pozycji przewijania lub uzyskanie jej bieżącego stanu. Aby utworzyć go z parametrami domyślnymi, użyj polecenia rememberScrollState()
.
@Composable private fun ScrollBoxesSmooth() { // Smoothly scroll 100px on first composition val state = rememberScrollState() LaunchedEffect(Unit) { state.animateScrollTo(100) } Column( modifier = Modifier .background(Color.LightGray) .size(100.dp) .padding(horizontal = 8.dp) .verticalScroll(state) ) { repeat(10) { Text("Item $it", modifier = Modifier.padding(2.dp)) } } }
Modyfikator przewijania
Modyfikator
scrollable
różni się od modyfikatorów przewijania tym, że scrollable
wykrywa gesty przewijania i rejestruje zmiany, ale nie przesuwa automatycznie zawartości. Zamiast tego uprawnienia są delegowane na użytkownika za pomocą parametru
ScrollableState
, który jest wymagany do prawidłowego działania tego modyfikatora.
Podczas tworzenia funkcji ScrollableState
musisz podać funkcję consumeScrollDelta
, która będzie wywoływana przy każdym kroku przewijania (za pomocą gestu, płynnego przewijania lub szybkiego przewijania) z wartością delta w pikselach. Ta funkcja musi zwracać ilość przewiniętej odległości, aby zdarzenie było prawidłowo propagowane w przypadku elementów zagnieżdżonych, które mają modyfikator scrollable
.
Poniższy fragment kodu wykrywa gesty i wyświetla wartość liczbową przesunięcia, ale nie przesuwa żadnych elementów:
@Composable private fun ScrollableSample() { // actual composable state var offset by remember { mutableStateOf(0f) } Box( Modifier .size(150.dp) .scrollable( orientation = Orientation.Vertical, // Scrollable state: describes how to consume // scrolling delta and update offset state = rememberScrollableState { delta -> offset += delta delta } ) .background(Color.LightGray), contentAlignment = Alignment.Center ) { Text(offset.toString()) } }
Przewijanie zagnieżdżone
Zagnieżdżone przewijanie to system, w którym wiele komponentów przewijania zawartych w sobie nawzajem współpracuje ze sobą, reagując na jeden gest przewijania i przekazując sobie informacje o zmianach przewijania.
System zagnieżdżonego przewijania umożliwia koordynację między komponentami, które można przewijać i które są połączone hierarchicznie (najczęściej przez wspólny element nadrzędny). Ten system łączy kontenery przewijane i umożliwia interakcję z różnicami przewijania, które są propagowane i udostępniane między nimi.
Compose udostępnia kilka sposobów obsługi zagnieżdżonego przewijania między komponentami. Typowym przykładem zagnieżdżonego przewijania jest lista w innej liście, a bardziej złożonym przypadkiem jest zwijany pasek narzędzi.
Automatyczne zagnieżdżone przewijanie
Proste zagnieżdżone przewijanie nie wymaga żadnych działań z Twojej strony. Gesty, które inicjują przewijanie, są automatycznie przekazywane z elementów podrzędnych do nadrzędnych. Oznacza to, że gdy element podrzędny nie może już przewijać, gest jest obsługiwany przez jego element nadrzędny.
Automatyczne zagnieżdżone przewijanie jest obsługiwane i dostępne od razu w przypadku niektórych komponentów i modyfikatorów Compose: verticalScroll
, horizontalScroll
, scrollable
, interfejsy API Lazy
i TextField
. Oznacza to, że gdy użytkownik przewija wewnętrzny element podrzędny zagnieżdżonych komponentów, poprzednie modyfikatory propagują delty przewijania do elementów nadrzędnych, które obsługują zagnieżdżone przewijanie.
Poniższy przykład przedstawia elementy z zastosowanym modyfikatorem
verticalScroll
w kontenerze, do którego również zastosowano modyfikator verticalScroll
.
@Composable private fun AutomaticNestedScroll() { val gradient = Brush.verticalGradient(0f to Color.Gray, 1000f to Color.White) Box( modifier = Modifier .background(Color.LightGray) .verticalScroll(rememberScrollState()) .padding(32.dp) ) { Column { repeat(6) { Box( modifier = Modifier .height(128.dp) .verticalScroll(rememberScrollState()) ) { Text( "Scroll here", modifier = Modifier .border(12.dp, Color.DarkGray) .background(brush = gradient) .padding(24.dp) .height(150.dp) ) } } } } }
Używanie modyfikatora nestedScroll
Jeśli chcesz utworzyć zaawansowane skoordynowane przewijanie między wieloma elementami, modyfikator nestedScroll
zapewni Ci większą elastyczność dzięki zdefiniowaniu zagnieżdżonej hierarchii przewijania. Jak wspomnieliśmy w poprzedniej sekcji, niektóre komponenty mają wbudowaną obsługę zagnieżdżonego przewijania. W przypadku komponentów kompozycyjnych, które nie są automatycznie przewijane, np. Box
lub Column
, delty przewijania w takich komponentach nie będą propagowane w systemie przewijania zagnieżdżonego i nie dotrą do NestedScrollConnection
ani do komponentu nadrzędnego. Aby rozwiązać ten problem, możesz użyć nestedScroll
, aby zapewnić obsługę innym komponentom, w tym komponentom niestandardowym.
Cykl zagnieżdżonego przewijania
Zagnieżdżony cykl przewijania to przepływ wartości delta przewijania, które są wysyłane w górę i w dół drzewa hierarchii przez wszystkie komponenty (lub węzły) należące do zagnieżdżonego systemu przewijania, np. za pomocą komponentów i modyfikatorów z możliwością przewijania lub nestedScroll
.
Fazy cyklu zagnieżdżonego przewijania
Gdy komponent z możliwością przewijania wykryje zdarzenie wywołujące (np. gest), zanim jeszcze zostanie wywołana rzeczywista czynność przewijania, wygenerowane wartości delta są wysyłane do zagnieżdżonego systemu przewijania i przechodzą przez 3 fazy: przed przewijaniem, wykorzystanie węzła i po przewijaniu.
W pierwszej fazie przed przewinięciem komponent, który otrzymał zdarzenie wywołujące, będzie wysyłać te zdarzenia w górę drzewa hierarchii do najwyższego elementu nadrzędnego. Zdarzenia delta będą się wtedy rozprzestrzeniać w dół, co oznacza, że będą przekazywane od nadrzędnego elementu głównego do elementu podrzędnego, który rozpoczął zagnieżdżony cykl przewijania.
Dzięki temu zagnieżdżone elementy przewijane (komponenty kompozycyjne korzystające z modyfikatorów nestedScroll
lub scrollable) mogą coś zrobić z wartością delta, zanim węzeł będzie mógł ją wykorzystać.
W fazie zużycia węzła sam węzeł wykorzysta wszystkie różnice, które nie zostały wykorzystane przez jego węzły nadrzędne. Wtedy następuje faktyczne przewijanie i jest ono widoczne.
W tym czasie dziecko może przewinąć pozostałą część strony lub tylko jej fragment. Pozostałe elementy zostaną przesłane z powrotem do góry, aby przejść fazę po przewinięciu.
W fazie po przewinięciu wszystko, czego węzeł nie wykorzystał, zostanie ponownie wysłane do jego elementów nadrzędnych.
Faza po przewinięciu działa podobnie jak faza przed przewinięciem, w której każdy z elementów nadrzędnych może zdecydować, czy chce wykorzystać zdarzenie, czy nie.
Podobnie jak w przypadku przewijania, po zakończeniu gestu przeciągnięcia intencje użytkownika mogą zostać przełożone na prędkość, która jest używana do szybkiego przewijania (przewijania za pomocą animacji) kontenera z możliwością przewijania. Szybkie przesunięcie jest też częścią zagnieżdżonego cyklu przewijania, a prędkości generowane przez zdarzenie przeciągania przechodzą przez podobne fazy: przed szybkim przesunięciem, zużycie węzła i po szybkim przesunięciu. Pamiętaj, że animacja przesunięcia jest powiązana tylko z gestem dotykowym i nie jest wywoływana przez inne zdarzenia, takie jak przewijanie za pomocą funkcji ułatwień dostępu lub sprzętu.
Uczestniczenie w cyklu zagnieżdżonego przewijania
Uczestnictwo w cyklu oznacza przechwytywanie, wykorzystywanie i raportowanie wykorzystania różnic wzdłuż hierarchii. Compose udostępnia zestaw narzędzi, które pozwalają wpływać na działanie zagnieżdżonego systemu przewijania i bezpośrednio z nim wchodzić w interakcję, np. gdy musisz coś zrobić z różnicami przewijania, zanim komponent z możliwością przewijania zacznie się przewijać.
Jeśli zagnieżdżony cykl przewijania jest systemem działającym na łańcuchu węzłów, modyfikator nestedScroll
umożliwia przechwytywanie i wstawianie zmian oraz wpływanie na dane (przyrosty przewijania) propagowane w łańcuchu. Ten modyfikator może być umieszczony w dowolnym miejscu w hierarchii i komunikuje się z zagnieżdżonymi instancjami modyfikatora przewijania w górę drzewa, dzięki czemu może udostępniać informacje za pomocą tego kanału. Podstawowymi elementami tego modyfikatora są NestedScrollConnection
i NestedScrollDispatcher
.
NestedScrollConnection
umożliwia reagowanie na fazy zagnieżdżonego cyklu przewijania i wpływanie na
zagnieżdżony system przewijania. Składa się z 4 metod wywołania zwrotnego, z których każda reprezentuje jedną z faz konsumpcji: przed i po przewinięciu oraz przed i po przesunięciu:
val nestedScrollConnection = object : NestedScrollConnection { override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { println("Received onPreScroll callback.") return Offset.Zero } override fun onPostScroll( consumed: Offset, available: Offset, source: NestedScrollSource ): Offset { println("Received onPostScroll callback.") return Offset.Zero } }
Każde wywołanie zwrotne zawiera też informacje o propagowanej wartości delta:available
wartość delta dla danej fazy i consumed
wartość delta wykorzystana w poprzednich fazach. Jeśli w dowolnym momencie chcesz przestać propagować zmiany w górę hierarchii, możesz użyć do tego zagnieżdżonego połączenia przewijania:
val disabledNestedScrollConnection = remember { object : NestedScrollConnection { override fun onPostScroll( consumed: Offset, available: Offset, source: NestedScrollSource ): Offset { return if (source == NestedScrollSource.SideEffect) { available } else { Offset.Zero } } } }
Wszystkie wywołania zwrotne zawierają informacje o NestedScrollSource
.
NestedScrollDispatcher
inicjuje zagnieżdżony cykl przewijania. Użycie dyspozytora i wywołanie jego metod
uruchamia cykl. Kontenery z możliwością przewijania mają wbudowany moduł wysyłający, który przesyła do systemu różnice zarejestrowane podczas gestów. Z tego powodu większość przypadków użycia dostosowywania zagnieżdżonego przewijania polega na używaniu NestedScrollConnection
zamiast dyspozytora, aby reagować na już istniejące delty, a nie wysyłać nowych.
Więcej informacji znajdziesz w sekcji NestedScrollDispatcherSample
.
Zmienianie rozmiaru obrazu podczas przewijania
Podczas przewijania przez użytkownika możesz utworzyć dynamiczny efekt wizualny, w którym rozmiar obrazu zmienia się w zależności od pozycji przewijania.
Zmienianie rozmiaru obrazu na podstawie pozycji przewijania
Ten fragment kodu pokazuje, jak zmienić rozmiar obrazu w elemencie LazyColumn
na podstawie pozycji przewijania w pionie. Obraz zmniejsza się, gdy użytkownik przewija w dół, i powiększa, gdy przewija w górę, pozostając w określonych granicach minimalnego i maksymalnego rozmiaru:
@Composable fun ImageResizeOnScrollExample( modifier: Modifier = Modifier, maxImageSize: Dp = 300.dp, minImageSize: Dp = 100.dp ) { var currentImageSize by remember { mutableStateOf(maxImageSize) } var imageScale by remember { mutableFloatStateOf(1f) } val nestedScrollConnection = remember { object : NestedScrollConnection { override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { // Calculate the change in image size based on scroll delta val delta = available.y val newImageSize = currentImageSize + delta.dp val previousImageSize = currentImageSize // Constrain the image size within the allowed bounds currentImageSize = newImageSize.coerceIn(minImageSize, maxImageSize) val consumed = currentImageSize - previousImageSize // Calculate the scale for the image imageScale = currentImageSize / maxImageSize // Return the consumed scroll amount return Offset(0f, consumed.value) } } } Box(Modifier.nestedScroll(nestedScrollConnection)) { LazyColumn( Modifier .fillMaxWidth() .padding(15.dp) .offset { IntOffset(0, currentImageSize.roundToPx()) } ) { // Placeholder list items items(100, key = { it }) { Text( text = "Item: $it", style = MaterialTheme.typography.bodyLarge ) } } Image( painter = ColorPainter(Color.Red), contentDescription = "Red color image", Modifier .size(maxImageSize) .align(Alignment.TopCenter) .graphicsLayer { scaleX = imageScale scaleY = imageScale // Center the image vertically as it scales translationY = -(maxImageSize.toPx() - currentImageSize.toPx()) / 2f } ) } }
Najważniejsze informacje o kodzie
- Ten kod używa
NestedScrollConnection
do przechwytywania zdarzeń przewijania. onPreScroll
oblicza zmianę rozmiaru obrazu na podstawie wartości delta przewijania.- Zmienna stanu
currentImageSize
przechowuje bieżący rozmiar obrazu, który mieści się w zakresie odminImageSize
domaxImageSize. imageScale
i jest wyznaczany na podstawie zmiennejcurrentImageSize
. - Wartości przesunięcia
LazyColumn
są oparte na wartościcurrentImageSize
. - W przypadku
Image
używany jest modyfikatorgraphicsLayer
, aby zastosować obliczoną skalę. - Symbol
translationY
w ramachgraphicsLayer
zapewnia, że obraz pozostanie wyśrodkowany w pionie podczas skalowania.
Wynik
Powyższy fragment kodu powoduje efekt skalowania obrazu podczas przewijania:
Współdziałanie zagnieżdżonego przewijania
Jeśli spróbujesz zagnieździć elementy z możliwością przewijania View
w komponentach z możliwością przewijania lub odwrotnie, możesz napotkać problemy. Najbardziej zauważalne będą sytuacje, w których przewijasz element podrzędny i docierasz do jego początku lub końca, a oczekujesz, że przewijanie przejmie element nadrzędny. Jednak to oczekiwane zachowanie może nie wystąpić lub może nie działać zgodnie z oczekiwaniami.
Ten problem wynika z oczekiwań wbudowanych w komponenty kompozycyjne z możliwością przewijania.
Komponenty z możliwością przewijania mają regułę „nested-scroll-by-default”, co oznacza, że każdy kontener z możliwością przewijania musi uczestniczyć w łańcuchu przewijania zagnieżdżonego zarówno jako element nadrzędny za pomocą NestedScrollConnection
, jak i jako element podrzędny za pomocą NestedScrollDispatcher
.
W takim przypadku element podrzędny będzie powodować zagnieżdżone przewijanie elementu nadrzędnego, gdy osiągnie granicę. Na przykład ta reguła umożliwia prawidłowe współdziałanie funkcji Compose Pager
i Compose LazyRow
. Jednak w przypadku przewijania w ramach interoperacyjności za pomocą ViewPager2
lub RecyclerView
, ponieważ nie implementują one NestedScrollingParent3
, ciągłe przewijanie z elementu podrzędnego do nadrzędnego nie jest możliwe.
Aby włączyć interfejs API współdziałania z zagnieżdżonym przewijaniem między elementami View
z możliwością przewijania a komponentami z możliwością przewijania, zagnieżdżonymi w obu kierunkach, możesz użyć interfejsu API współdziałania z zagnieżdżonym przewijaniem, aby rozwiązać te problemy w tych scenariuszach.
Współpracujący rodzic View
z dzieckiem ComposeView
Współpracujący element nadrzędny View
to element, który implementuje NestedScrollingParent3
, dzięki czemu może otrzymywać delty przewijania ze współpracującego zagnieżdżonego elementu podrzędnego. ComposeView
zachowywałby się w tym przypadku jak dziecko i musiałby (pośrednio) zaimplementować NestedScrollingChild3
.
Przykładem współpracującego rodzica jest
androidx.coordinatorlayout.widget.CoordinatorLayout
.
Jeśli potrzebujesz interoperacyjności zagnieżdżonego przewijania między przewijanymi View
kontenerami nadrzędnymi
a zagnieżdżonymi przewijanymi komponentami kompozycyjnymi, możesz użyć rememberNestedScrollInteropConnection()
.
rememberNestedScrollInteropConnection()
umożliwia i zapamiętuje
NestedScrollConnection
umożliwiające zagnieżdżone przewijanie między elementem nadrzędnym View
, który implementuje
NestedScrollingParent3
a elementem podrzędnym Compose. Należy go używać w połączeniu z modyfikatorem nestedScroll
. Przewijanie zagnieżdżone jest domyślnie włączone po stronie Compose, więc możesz użyć tego połączenia, aby włączyć przewijanie zagnieżdżone po stronie View
i dodać niezbędną logikę łączącą Views
z komponentami kompozycyjnymi.
Częstym przypadkiem użycia jest użycie CoordinatorLayout
, CollapsingToolbarLayout
i komponentu podrzędnego, jak w tym przykładzie:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="100dp" android:fitsSystemWindows="true"> <com.google.android.material.appbar.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <!--...--> </com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.AppBarLayout> <androidx.compose.ui.platform.ComposeView android:id="@+id/compose_view" app:layout_behavior="@string/appbar_scrolling_view_behavior" android:layout_width="match_parent" android:layout_height="match_parent"/> </androidx.coordinatorlayout.widget.CoordinatorLayout>
W aktywności lub fragmencie musisz skonfigurować komponent kompozycyjny podrzędny i wymagany NestedScrollConnection
:
open class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) findViewById<ComposeView>(R.id.compose_view).apply { setContent { val nestedScrollInterop = rememberNestedScrollInteropConnection() // Add the nested scroll connection to your top level @Composable element // using the nestedScroll modifier. LazyColumn(modifier = Modifier.nestedScroll(nestedScrollInterop)) { items(20) { item -> Box( modifier = Modifier .padding(16.dp) .height(56.dp) .fillMaxWidth() .background(Color.Gray), contentAlignment = Alignment.Center ) { Text(item.toString()) } } } } } } }
Funkcja kompozycyjna nadrzędna zawierająca element podrzędny AndroidView
Ten scenariusz obejmuje implementację zagnieżdżonego interfejsu API do przewijania na platformie Compose – gdy masz nadrzędną funkcję kompozycyjną zawierającą podrzędną funkcję kompozycyjną AndroidView
. Element AndroidView
implementuje interfejs NestedScrollDispatcher
, ponieważ jest elementem podrzędnym elementu przewijanego Compose, a także interfejs NestedScrollingParent3
, ponieważ jest elementem nadrzędnym elementu przewijanego View
. Komponent nadrzędny będzie
wtedy mógł otrzymywać delty zagnieżdżonego przewijania z zagnieżdżonego komponentu podrzędnego z możliwością przewijania
View
.
Poniższy przykład pokazuje, jak w tym scenariuszu można osiągnąć współdziałanie zagnieżdżonego przewijania wraz z rozwijanym paskiem narzędzi Compose:
@Composable
private fun NestedScrollInteropComposeParentWithAndroidChildExample() {
val toolbarHeightPx = with(LocalDensity.current) { ToolbarHeight.roundToPx().toFloat() }
val toolbarOffsetHeightPx = remember { mutableStateOf(0f) }
// Sets up the nested scroll connection between the Box composable parent
// and the child AndroidView containing the RecyclerView
val nestedScrollConnection = remember {
object : NestedScrollConnection {
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
// Updates the toolbar offset based on the scroll to enable
// collapsible behaviour
val delta = available.y
val newOffset = toolbarOffsetHeightPx.value + delta
toolbarOffsetHeightPx.value = newOffset.coerceIn(-toolbarHeightPx, 0f)
return Offset.Zero
}
}
}
Box(
Modifier
.fillMaxSize()
.nestedScroll(nestedScrollConnection)
) {
TopAppBar(
modifier = Modifier
.height(ToolbarHeight)
.offset { IntOffset(x = 0, y = toolbarOffsetHeightPx.value.roundToInt()) }
)
AndroidView(
{ context ->
LayoutInflater.from(context)
.inflate(R.layout.view_in_compose_nested_scroll_interop, null).apply {
with(findViewById<RecyclerView>(R.id.main_list)) {
layoutManager = LinearLayoutManager(context, VERTICAL, false)
adapter = NestedScrollInteropAdapter()
}
}.also {
// Nested scrolling interop is enabled when
// nested scroll is enabled for the root View
ViewCompat.setNestedScrollingEnabled(it, true)
}
},
// ...
)
}
}
private class NestedScrollInteropAdapter :
Adapter<NestedScrollInteropAdapter.NestedScrollInteropViewHolder>() {
val items = (1..10).map { it.toString() }
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): NestedScrollInteropViewHolder {
return NestedScrollInteropViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false)
)
}
override fun onBindViewHolder(holder: NestedScrollInteropViewHolder, position: Int) {
// ...
}
class NestedScrollInteropViewHolder(view: View) : ViewHolder(view) {
fun bind(item: String) {
// ...
}
}
// ...
}
Ten przykład pokazuje, jak używać interfejsu API z modyfikatorem scrollable
:
@Composable
fun ViewInComposeNestedScrollInteropExample() {
Box(
Modifier
.fillMaxSize()
.scrollable(rememberScrollableState {
// View component deltas should be reflected in Compose
// components that participate in nested scrolling
it
}, Orientation.Vertical)
) {
AndroidView(
{ context ->
LayoutInflater.from(context)
.inflate(android.R.layout.list_item, null)
.apply {
// Nested scrolling interop is enabled when
// nested scroll is enabled for the root View
ViewCompat.setNestedScrollingEnabled(this, true)
}
}
)
}
}
Ten przykład pokazuje, jak interfejs API współdziałania z zagnieżdżonym przewijaniem jest używany z BottomSheetDialogFragment
, aby uzyskać prawidłowe działanie funkcji przeciągania i zamykania:
class BottomSheetFragment : BottomSheetDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val rootView: View = inflater.inflate(R.layout.fragment_bottom_sheet, container, false)
rootView.findViewById<ComposeView>(R.id.compose_view).apply {
setContent {
val nestedScrollInterop = rememberNestedScrollInteropConnection()
LazyColumn(
Modifier
.nestedScroll(nestedScrollInterop)
.fillMaxSize()
) {
item {
Text(text = "Bottom sheet title")
}
items(10) {
Text(
text = "List item number $it",
modifier = Modifier.fillMaxWidth()
)
}
}
}
return rootView
}
}
}
Pamiętaj, że
rememberNestedScrollInteropConnection()
zainstaluje
NestedScrollConnection
w elemencie, do którego go dołączysz. NestedScrollConnection
odpowiada za przesyłanie zmian z poziomu Compose na poziom View
. Umożliwia to elementowi uczestniczenie w przewijaniu zagnieżdżonym, ale nie włącza automatycznie przewijania elementów. W przypadku komponentów kompozycyjnych, których nie można przewijać automatycznie, takich jak Box
lub Column
, różnice przewijania w takich komponentach nie będą propagowane w systemie przewijania zagnieżdżonego, a różnice nie dotrą do elementu NestedScrollConnection
dostarczonego przez rememberNestedScrollInteropConnection()
, dlatego nie dotrą do komponentu nadrzędnego View
. Aby rozwiązać ten problem, upewnij się, że do tych typów zagnieżdżonych funkcji kompozycyjnych ustawiasz też modyfikatory z możliwością przewijania. Więcej informacji znajdziesz w poprzedniej sekcji dotyczącej zagnieżdżonego przewijania.
Rodzic niechętny do współpracy View
z dzieckiem ComposeView
Widok nie współpracujący to taki, który nie implementuje niezbędnych interfejsów po stronie View
.NestedScrolling
Oznacza to, że zagnieżdżone przewijanie nie działa od razu w przypadku tych Views
. Nie współpracujące Views
to RecyclerView
i ViewPager2
.
Dodatkowe materiały
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy JavaScript jest wyłączony.
- Omówienie gestów
- Migracja z
CoordinatorLayout
do Compose - Korzystanie z widoków w Compose