اصلاح کننده های اسکرول
اصلاحکنندههای verticalScroll و horizontalScroll سادهترین راه را برای کاربر فراهم میکنند که به کاربر اجازه میدهد یک عنصر را زمانی که محدوده محتویات آن بزرگتر از حداکثر محدودیت اندازه آن است، اسکرول کند. با اصلاحکنندههای verticalScroll و horizontalScroll نیازی به ترجمه یا افست کردن محتوا ندارید.
@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)) } } }

ScrollState به شما امکان می دهد موقعیت اسکرول را تغییر دهید یا وضعیت فعلی آن را بدست آورید. برای ایجاد آن با پارامترهای پیش فرض، از 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)) } } }
اصلاح کننده قابل پیمایش
اصلاحکننده scrollable با اصلاحکنندههای پیمایشی تفاوت دارد زیرا scrollable حرکات اسکرول را تشخیص میدهد و دلتاها را میگیرد، اما محتویات آن را به طور خودکار تعدیل نمیکند. در عوض از طریق ScrollableState به کاربر واگذار میشود، که برای درست کار کردن این اصلاحکننده لازم است.
هنگام ساخت ScrollableState باید یک تابع consumeScrollDelta ارائه کنید که در هر مرحله اسکرول (با ورودی اشاره، اسکرول صاف یا پرت کردن) با دلتا به پیکسل فراخوانی می شود. این تابع باید مقدار مسافت پیمایش مصرف شده را برگرداند تا اطمینان حاصل شود که در مواردی که عناصر تودرتو که دارای اصلاح کننده scrollable هستند، رویداد به درستی منتشر می شود.
قطعه زیر ژستها را تشخیص میدهد و یک مقدار عددی برای یک افست نمایش میدهد، اما هیچ عنصری را افست نمیکند:
@Composable private fun ScrollableSample() { // actual composable state var offset by remember { mutableFloatStateOf(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()) } }

پیمایش تو در تو
پیمایش تودرتو سیستمی است که در آن چندین مؤلفه اسکرول موجود در یکدیگر با واکنش به یک حرکت پیمایشی واحد و ارتباط دلتاهای پیمایشی (تغییرات) با هم کار می کنند.
سیستم پیمایش تو در تو، هماهنگی بین اجزایی که قابل پیمایش هستند و به صورت سلسله مراتبی به هم مرتبط هستند (اغلب با به اشتراک گذاری یک والد) امکان پذیر است. این سیستم کانتینرهای پیمایشی را به هم پیوند میدهد و امکان تعامل با دلتاهای پیمایشی را میدهد که در حال انتشار و اشتراکگذاری بین آنها هستند.
Compose راههای متعددی را برای مدیریت پیمایش تودرتو بین اجزای سازنده فراهم میکند. یک مثال معمولی از پیمایش تودرتو، فهرستی در داخل فهرست دیگر است، و مورد پیچیدهتر، یک نوار ابزار در حال جمع شدن است.
پیمایش تو در تو خودکار
پیمایش تو در تو ساده نیازی به هیچ اقدامی از جانب شما ندارد. حرکاتی که حرکت پیمایشی را آغاز میکنند بهطور خودکار از فرزندان به والدین منتشر میشوند، به طوری که وقتی کودک نمیتواند بیشتر پیمایش کند، ژست توسط عنصر والد آن کنترل میشود.
پیمایش تو در تو خودکار توسط برخی از مؤلفهها و اصلاحکنندههای Compose پشتیبانی و ارائه میشود: verticalScroll ، horizontalScroll ، scrollable ، Lazy API و TextField . این بدان معناست که وقتی کاربر یک فرزند درونی اجزای تودرتو را پیمایش میکند، اصلاحکنندههای قبلی دلتاهای پیمایشی را به والدینی که پشتیبانی پیمایش تودرتو دارند منتشر میکنند.
مثال زیر عناصری را نشان میدهد که یک اصلاحکننده verticalScroll روی آنها در داخل یک ظرف اعمال شده است که یک اصلاحکننده 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) ) } } } } }

با استفاده از اصلاح کننده nestedScroll
اگر نیاز به ایجاد یک اسکرول هماهنگ پیشرفته بین چندین عنصر دارید، اصلاح کننده nestedScroll با تعریف سلسله مراتب پیمایش تودرتو انعطاف پذیری بیشتری به شما می دهد. همانطور که در بخش قبل ذکر شد، برخی از مؤلفه ها دارای پشتیبانی داخلی تو در تو هستند. با این حال، برای کامپوزیتیهایی که بهطور خودکار قابل پیمایش نیستند، مانند Box یا Column ، دلتاهای پیمایشی روی چنین مؤلفههایی در سیستم پیمایش تودرتو منتشر نمیشوند و دلتاها به NestedScrollConnection یا مؤلفه والد نمیرسند. برای حل این مشکل، میتوانید از nestedScroll برای ارائه چنین پشتیبانی به سایر مؤلفهها، از جمله مؤلفههای سفارشی، استفاده کنید.
چرخه پیمایش تو در تو
چرخه پیمایش تودرتو، جریان دلتاهای پیمایشی است که از طریق تمام مؤلفهها (یا گرهها) که بخشی از سیستم پیمایش تودرتو هستند، بهعنوان مثال با استفاده از مؤلفهها و اصلاحکنندههای قابل پیمایش یا nestedScroll به بالا و پایین درخت سلسله مراتب ارسال میشوند.
مراحل چرخه پیمایش تو در تو
هنگامی که یک رویداد ماشه (به عنوان مثال، یک حرکت) توسط یک مؤلفه قابل پیمایش شناسایی می شود، قبل از اینکه عمل پیمایش واقعی انجام شود، دلتاهای تولید شده به سیستم پیمایش تو در تو فرستاده می شوند و از سه مرحله عبور می کنند: پیش اسکرول، مصرف گره و پس از پیمایش.

در مرحله اول، قبل از اسکرول، مؤلفه ای که دلتاهای رویداد ماشه را دریافت کرده است، آن رویدادها را از طریق درخت سلسله مراتب به بالاترین والد ارسال می کند. سپس رویدادهای دلتا به سمت پایین حباب می شوند، به این معنی که دلتاها از ریشه ترین والد به سمت فرزندی که چرخه پیمایش تودرتو را شروع کرده است، منتشر می شود.

این به والدین پیمایش تودرتو (کامپوزیشنها با استفاده از nestedScroll یا اصلاحکنندههای قابل پیمایش) این فرصت را میدهد تا قبل از اینکه خود گره بتواند آن را مصرف کند، کاری با دلتا انجام دهد.

در مرحله مصرف گره، خود گره از دلتای استفاده می کند که توسط والدینش استفاده نشده است. این زمانی است که حرکت اسکرول در واقع انجام شده و قابل مشاهده است.

در این مرحله، کودک ممکن است تمام یا بخشی از اسکرول باقیمانده را مصرف کند. هر چیزی که باقی مانده باشد برای گذراندن مرحله پس از اسکرول به بالا ارسال می شود.
در نهایت، در مرحله پس از اسکرول، هر چیزی که خود گره مصرف نکرده باشد، دوباره برای مصرف به اجداد خود ارسال می شود.

مرحله پس از اسکرول به روشی مشابه مرحله قبل از اسکرول عمل می کند، جایی که هر یک از والدین ممکن است مصرف کنند یا نه.

به طور مشابه برای اسکرول، هنگامی که یک حرکت کشیدن به پایان می رسد، قصد کاربر ممکن است به سرعتی تبدیل شود که برای پرت کردن (پیمایش با استفاده از انیمیشن) ظرف قابل پیمایش استفاده می شود. پرت کردن نیز بخشی از چرخه پیمایش تو در تو است و سرعتهای ایجاد شده توسط رویداد درگ مراحل مشابهی را طی میکنند: پیش پرتاب، مصرف گره و پس از پرتاب. توجه داشته باشید که انیمیشن پرت کردن فقط با ژست لمسی مرتبط است و با رویدادهای دیگر مانند a11y یا اسکرول سخت افزاری فعال نمی شود.
در چرخه پیمایش تودرتو شرکت کنید
مشارکت در چرخه به معنای رهگیری، مصرف و گزارش مصرف دلتاها در امتداد سلسله مراتب است. Compose مجموعهای از ابزارها را برای تأثیرگذاری بر نحوه عملکرد سیستم پیمایش تودرتو و نحوه تعامل مستقیم با آن فراهم میکند، برای مثال زمانی که باید کاری را با دلتاهای اسکرول انجام دهید قبل از اینکه یک جزء قابل پیمایش حتی شروع به پیمایش کند.
اگر چرخه پیمایش تودرتو سیستمی است که بر روی زنجیره ای از گره ها عمل می کند، اصلاح کننده nestedScroll راهی برای رهگیری و درج در این تغییرات و تأثیرگذاری بر داده ها (دلتاهای اسکرول) است که در زنجیره منتشر می شوند. این اصلاح کننده را می توان در هر جایی از سلسله مراتب قرار داد و با نمونه های اصلاح کننده اسکرول تودرتو در بالای درخت ارتباط برقرار می کند تا بتواند اطلاعات را از طریق این کانال به اشتراک بگذارد. بلوک های سازنده این اصلاح کننده NestedScrollConnection و NestedScrollDispatcher هستند.
NestedScrollConnection راهی برای پاسخ به مراحل چرخه پیمایش تودرتو و تأثیرگذاری بر سیستم پیمایش تو در تو فراهم می کند. این متشکل از چهار روش برگشت تماس است که هر کدام یکی از مراحل مصرف را نشان میدهد: پیش/پس از اسکرول و پیش/پس از پرتاب:
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 } }
هر فراخوانی همچنین اطلاعاتی در مورد دلتای در حال انتشار می دهد: دلتای available برای آن فاز خاص و دلتای consumed مصرف شده در فازهای قبلی. اگر در هر نقطه ای بخواهید انتشار دلتا در سلسله مراتب را متوقف کنید، می توانید از اتصال پیمایش تودرتو برای این کار استفاده کنید:
val disabledNestedScrollConnection = remember { object : NestedScrollConnection { override fun onPostScroll( consumed: Offset, available: Offset, source: NestedScrollSource ): Offset { return if (source == NestedScrollSource.SideEffect) { available } else { Offset.Zero } } } }
همه فراخوانها اطلاعاتی در مورد نوع NestedScrollSource ارائه میکنند.
NestedScrollDispatcher چرخه پیمایش تودرتو را مقداردهی اولیه می کند. استفاده از دیسپچر و فراخوانی متدهای آن چرخه را راه اندازی می کند. ظروف قابل پیمایش دارای یک توزیع کننده داخلی هستند که دلتاهای گرفته شده در حین حرکات را به سیستم ارسال می کند. به همین دلیل، بیشتر موارد استفاده از سفارشی کردن پیمایش تودرتو شامل استفاده از NestedScrollConnection به جای توزیع کننده، برای واکنش به دلتاهای موجود به جای ارسال موارد جدید است. برای استفاده بیشتر به NestedScrollDispatcherSample مراجعه کنید.
تغییر اندازه یک تصویر در اسکرول
همانطور که کاربر پیمایش می کند، می توانید یک جلوه بصری پویا ایجاد کنید که در آن اندازه تصویر بر اساس موقعیت اسکرول تغییر می کند.
اندازه تصویر را بر اساس موقعیت اسکرول تغییر دهید
این قطعه تغییر اندازه یک تصویر را در LazyColumn بر اساس موقعیت اسکرول عمودی نشان می دهد. با اسکرول کردن کاربر به پایین، تصویر کوچک میشود، و با حرکت به سمت بالا بزرگ میشود و در محدوده حداقل و حداکثر اندازه تعریف شده باقی میماند:
@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 } ) } }
نکات کلیدی در مورد کد
- این کد از یک
NestedScrollConnectionبرای رهگیری رویدادهای اسکرول استفاده می کند. -
onPreScrollتغییر اندازه تصویر را بر اساس دلتای اسکرول محاسبه می کند. - متغیر حالت
currentImageSizeاندازه فعلی تصویر را ذخیره می کند که بینminImageSizeوmaxImageSize. imageScaleازcurrentImageSizeمشتق شده است. -
LazyColumnبر اساسcurrentImageSizeجابجا می شود. -
Imageاز یک اصلاح کنندهgraphicsLayerبرای اعمال مقیاس محاسبه شده استفاده می کند. -
translationYدرgraphicsLayerتضمین می کند که تصویر به صورت عمودی در مرکز باقی می ماند.
نتیجه
قطعه قبلی منجر به یک جلوه تصویر مقیاسپذیر در اسکرول میشود:
تودرتو پیمایش interop
وقتی سعی میکنید عناصر View قابل پیمایش را در ترکیببندیهای قابل پیمایش قرار دهید، یا برعکس، ممکن است با مشکلاتی مواجه شوید. قابل توجه ترین موارد زمانی اتفاق می افتد که شما کودک را اسکرول می کنید و به مرزهای شروع یا پایان آن می رسید و انتظار دارید که والدین پیمایش را بر عهده بگیرند. با این حال، این رفتار مورد انتظار یا ممکن است اتفاق نیفتد یا ممکن است مطابق انتظار عمل نکند.
این موضوع نتیجه انتظارات ساخته شده در کامپوزیشن های قابل پیمایش است. ترکیبهای قابل پیمایش دارای قانون «پیمایش تودرتو» هستند، به این معنی که هر ظرف قابل پیمایش باید در زنجیره پیمایش تودرتو مشارکت کند، هم بهعنوان والد از طریق NestedScrollConnection و هم بهعنوان فرزند از طریق NestedScrollDispatcher . هنگامی که کودک در محدوده است، کودک یک طومار تو در تو را برای والدین می راند. به عنوان مثال، این قانون به Compose Pager و Compose LazyRow اجازه می دهد تا به خوبی با هم کار کنند. با این حال، هنگامی که پیمایش قابلیت همکاری با ViewPager2 یا RecyclerView انجام میشود، چون NestedScrollingParent3 پیادهسازی نمیکنند، پیمایش مداوم از فرزند به والد امکانپذیر نیست.
برای فعال کردن Nested Scroll Interop API بین عناصر View قابل پیمایش و composableهای قابل پیمایش، تودرتو در هر دو جهت، میتوانید از API interop پیمایش تودرتو برای کاهش این مشکلات در سناریوهای زیر استفاده کنید.
یک View والدین همکار که حاوی ComposeView فرزند است
یک View والد همکار، نمایشی است که قبلاً NestedScrollingParent3 پیادهسازی میکند و بنابراین میتواند دلتاهای پیمایشی را از یک فرزند تودرتوی همکاریکننده دریافت کند. ComposeView در این مورد به عنوان یک کودک عمل می کند و باید (غیر مستقیم) NestedScrollingChild3 پیاده سازی کند. یک نمونه از والدین همکار androidx.coordinatorlayout.widget.CoordinatorLayout است.
اگر به قابلیت همکاری پیمایش تودرتو بین View کانتینرهای والد قابل پیمایش و composableهای فرزند قابل پیمایش تودرتو نیاز دارید، می توانید از rememberNestedScrollInteropConnection() استفاده کنید.
rememberNestedScrollInteropConnection() اجازه می دهد و NestedScrollConnection به خاطر می آورد که قابلیت همکاری پیمایش تودرتو را بین یک View والد که NestedScrollingParent3 اجرا می کند و یک فرزند Compose را فعال می کند. این باید همراه با یک اصلاح کننده nestedScroll استفاده شود. از آنجایی که پیمایش تودرتو به طور پیشفرض در سمت Compose فعال است، میتوانید از این اتصال برای فعال کردن پیمایش تودرتو در سمت View و اضافه کردن منطق چسب لازم بین Views و Composable استفاده کنید.
یک مورد استفاده مکرر استفاده از CoordinatorLayout ، CollapsingToolbarLayout و یک فرزند composable است که در این مثال نشان داده شده است:
<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>
در Activity یا Fragment خود، باید فرزند خود را composable و 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()) } } } } } } }
یک والد قابل ترکیب حاوی AndroidView فرزند
این سناریو اجرای API interop پیمایش تودرتو در سمت Compose را پوشش میدهد - زمانی که یک Composable والدین حاوی AndroidView فرزند دارید. AndroidView NestedScrollDispatcher پیادهسازی میکند، زیرا بهعنوان فرزند برای یک والد پیمایشی Compose و همچنین NestedScrollingParent3 عمل میکند، زیرا بهعنوان والد برای یک فرزند درحال پیمایش View عمل میکند. سپس والد نوشتن میتواند دلتاهای پیمایش تودرتو را از View فرزند قابل پیمایش تودرتو دریافت کند.
مثال زیر نشان میدهد که چگونه میتوانید در این سناریو، به همراه نوار ابزار جمعشده Compose، به interop پیمایش تودرتو دست یابید:
@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) {
// ...
}
}
// ...
}
این مثال نشان می دهد که چگونه می توانید از API با یک اصلاح کننده 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)
}
}
)
}
}
و در نهایت، این مثال نشان می دهد که چگونه API interop پیمایش تودرتو با BottomSheetDialogFragment برای دستیابی به یک رفتار کشیدن و رد کردن موفقیت آمیز استفاده می شود:
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
}
}
}
توجه داشته باشید که rememberNestedScrollInteropConnection() یک NestedScrollConnection در عنصری که آن را به آن متصل می کنید نصب می کند. NestedScrollConnection مسئول انتقال دلتاها از سطح Compose به سطح View است. این عنصر را قادر می سازد تا در پیمایش تودرتو شرکت کند، اما پیمایش عناصر را به صورت خودکار فعال نمی کند. برای کامپوزیشنهایی که بهطور خودکار قابل پیمایش نیستند، مانند Box یا Column ، دلتاهای پیمایشی روی چنین مؤلفههایی در سیستم پیمایش تودرتو منتشر نمیشوند و دلتاها به NestedScrollConnection ارائهشده توسط rememberNestedScrollInteropConnection() نمیرسند، بنابراین آن دلتاها به View Parent نمیرسند. برای حل این مشکل، مطمئن شوید که اصلاحکنندههای قابل پیمایش را نیز برای این نوع ترکیبپذیرهای تودرتو تنظیم کردهاید. برای اطلاعات بیشتر می توانید به بخش قبلی در مورد پیمایش تودرتو مراجعه کنید.
یک View والدین غیر همکار که حاوی ComposeView فرزند است
یک View غیر همکار، نمایشی است که رابط های NestedScrolling لازم را در سمت View پیاده سازی نمی کند. توجه داشته باشید که این بدان معنی است که قابلیت همکاری پیمایش تودرتو با این Views به خوبی کار نمی کند. Views غیر همکار RecyclerView و ViewPager2 هستند.
منابع اضافی
{% کلمه به کلمه %}برای شما توصیه می شود
- توجه: وقتی جاوا اسکریپت خاموش است، متن پیوند نمایش داده می شود
- ژست ها را درک کنید
- برای نوشتن،
CoordinatorLayoutمهاجرت کنید - استفاده از Views در Compose