ایجاد چیدمان‌های پیمایش‌شدنی برای تلویزیون

برای برنامه‌های تلویزیون، تجربه مرور به پیمایش کارآمد مبتنی بر تمرکز متکی است. بااستفاده از چیدمان‌های تنبل Compose Foundation استاندارد، می‌توانید فهرست‌های عمودی و افقی کارآمدی ایجاد کنید که به‌طور خودکار پیمایش متمرکز را مدیریت می‌کنند تا موارد فعال را در دید نگه دارند.

رفتار پیمایش پیش‌فرض بهینه‌شده برای تلویزیون

از Compose Foundation نسخه ۱.۷.۰، چیدمان‌های تنبل استاندارد (مانند LazyRow و LazyColumn) شامل پشتیبانی داخلی برای ویژگی‌های جای‌یابی تمرکز هستند. این روش توصیه‌شده برای ساخت کاتالوگ برای برنامه‌های تلویزیون است زیرا کمک می‌کند موارد متمرکزشده قابل‌مشاهده باقی بمانند و به‌طور شهودی برای کاربر قرار گیرند.

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

import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items

@Composable
fun MovieCatalog(movies: List<Movie>) {
    LazyRow {
        items(movies) { movie ->
            MovieCard(
                movie = movie,
                onClick = { /* Handle click */ }
            )
        }
    }
}

سفارشی‌سازی کردن رفتار پیمایش با BringIntoViewSpec

اگر طراحی شما به نقطه «محوری» خاصی نیاز دارد (برای مثال، نگه داشتن مورد متمرکزشده دقیقاً در فاصله ۳۰٪ از لبه چپ)، می‌توانید رفتار پیمایش را بااستفاده از BringIntoViewSpec سفارشی‌سازی کنید. این ویژگی جایگزین عملکرد قدیمی‌تر pivotOffsets می‌شود و به شما امکان می‌دهد دقیقاً تعریف کنید که نمای هدف چگونه باید پیمایش شود تا با مورد متمرکزشده مطابقت داشته باشد.

۱. تعریف کردن BringIntoViewSpec سفارشی

ترکیب‌پذیر کمکی زیر به شما امکان می‌دهد «محوری» را براساس کسر والد و فرزند تعریف کنید. ‫parentFraction تعیین می‌کند که مورد در کجای ظرف قرار بگیرد و childFraction تعیین می‌کند که کدام بخش از مورد با آن نقطه تراز شود.

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PositionFocusedItemInLazyLayout(
    parentFraction: Float = 0.3f,
    childFraction: Float = 0f,
    content: @Composable () -> Unit,
) {
    val bringIntoViewSpec = remember(parentFraction, childFraction) {
        object : BringIntoViewSpec {
            override fun calculateScrollDistance(
                offset: Float,       // Item's initial position
                size: Float,         // Item's size
                containerSize: Float // Container's size
            ): Float {
                // Calculate the offset position of the item's leading edge.
                val initialTargetForLeadingEdge =
                    parentFraction * containerSize - (childFraction * size)
                // If the item fits in the container, and scrolling would cause
                // its trailing edge to be clipped, adjust targetForLeadingEdge
                // to prevent over-scrolling near the end of list.
                val targetForLeadingEdge = if (size <= containerSize &&
                    (containerSize - initialTargetForLeadingEdge) < size) {
                    // If clipped, align the item's trailing edge with the
                    // container's trailing edge.
                    containerSize - size
                } else {
                    initialTargetForLeadingEdge
                }
                // Return scroll distance relative to initial item position.
                return offset - targetForLeadingEdge
            }
        }
    }

    // Apply the spec to all scrollables in the hierarchy
    CompositionLocalProvider(
        LocalBringIntoViewSpec provides bringIntoViewSpec,
        content = content,
    )
}

۲. اعمال مشخصات سفارشی

برای اعمال موقعیت‌یابی، چیدمان‌هایتان را با کمک‌کننده بپوشانید. این کار برای ایجاد «خط تمرکز یکسان» در ردیف‌های مختلف کاتالوگ شما مفید است.

PositionFocusedItemInLazyLayout(
    parentFraction = 0.3f, // Pivot 30% from the edge
    childFraction = 0.5f   // Center of the item aligns with the pivot
) {
    LazyColumn {
        items(sectionList) { section ->
            // This row and its items will respect the 30% pivot
            LazyRow { /* ... */ }
        }
    }
}

۳. انصراف دادن از چیدمان‌های تودرتوی خاص

اگر چیدمان تودرتوی خاصی دارید که باید به‌جای محور سفارشی شما از رفتار پیمایش استاندارد استفاده کند، DefaultBringIntoViewSpec را ارائه دهید:

private val DefaultBringIntoViewSpec = object : BringIntoViewSpec {}

PositionFocusedItemInLazyLayout {
    LazyColumn {
        item {
            // This row will ignore the custom pivot and use default behavior
            CompositionLocalProvider(LocalBringIntoViewSpec provides DefaultBringIntoViewSpec) {
                LazyRow { /* ... */ }
            }
        }
    }
}

درواقع، با ارسال یک BringIntoViewSpec خالی، رفتار پیش‌فرض چارچوب فعال می‌شود تا کنترل را به‌دست بگیرد.

انتقال از TV Foundation به Compose Foundation

چیدمان‌های تنبل مختص تلویزیون در androidx.tv.foundation منسوخ شده‌اند و به‌جای آن‌ها از چیدمان‌های استاندارد Compose Foundation استفاده می‌شود.

به‌روزرسانی‌های وابستگی

تأیید کنید که build.gradle شما از نسخه ۱.۷.۰ یا بالاتر برای موارد زیر استفاده می‌کند:

  • androidx.compose.foundation
  • androidx.compose.runtime

تخصیص دادن مؤلفه

برای انتقال، واردات خود را به‌روز کنید و پیشوند Tv را از مؤلفه‌های خود بردارید:

دستگاه تلویزیون منسوخ‌شده جایگزین Compose Foundation
TvLazyRow LazyRow
TvLazyColumn LazyColumn
TvLazyHorizontalGrid LazyHorizontalGrid
TvLazyVerticalGrid LazyVerticalGrid
pivotOffsets BringIntoViewSpec (ازطریق LocalBringIntoViewSpec)