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

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

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

از Compose Foundation 1.7.0، چیدمان‌های تنبل استاندارد (مثل 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 خالی، رفتار پیش‌فرض چارچوب فعال می‌شود.

انتقال از «شالوده تلویزیون» به «شالوده Compose»

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

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

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

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

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

برای انتقال، وارد کردن‌هایتان را به‌روز کنید و پیشوند Tv را از عناصرتان بردارید:

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