টিভির জন্য স্ক্রল করা যায় এমন লেআউট তৈরি করা

টিভি অ্যাপের ক্ষেত্রে, ব্রাউজিং অভিজ্ঞতা নির্ভর করে ফোকাস-ভিত্তিক নেভিগেশনের দক্ষতার উপর। স্ট্যান্ডার্ড Compose Foundation লেজি লেআউট ব্যবহার করে, আপনি পারফর্ম্যান্স-ভিত্তিক উল্লম্ব ও অনুভূমিক তালিকা তৈরি করতে পারবেন যা অ্যাক্টিভ আইটেমকে ভিউতে রাখার জন্য ফোকাস-চালিত স্ক্রলিং অটোমেটিক ম্যানেজ করে।

টিভির জন্য অপ্টিমাইজ করা ডিফল্ট স্ক্রল করার আচরণ

Compose Foundation 1.7.0 থেকে শুরু করে, স্ট্যান্ডার্ড লেজি লেআউটে (যেমন LazyRow এবং LazyColumn) ফোকাস-পজিশনিং ফিচারের জন্য বিল্ট-ইন সহায়তা অন্তর্ভুক্ত থাকে। টিভি অ্যাপের জন্য ক্যাটালগ তৈরি করার এটি সাজেস্ট করা পদ্ধতি কারণ এটি ফোকাস করা আইটেমগুলিকে দৃশ্যমান রাখতে এবং ব্যবহারকারীর জন্য স্বজ্ঞাতভাবে পজিশন করতে সাহায্য করে।

একটি সাধারণ স্ক্রল করা যায় এমন তালিকা প্রয়োগ করতে, স্ট্যান্ডার্ড লেজি কম্পোনেন্ট ব্যবহার করুন। এইসব কম্পোনেন্ট অটোমেটিক D-pad নেভিগেশন ম্যানেজ করে এবং ফোকাস করা আইটেমকে ভিউতে নিয়ে আসে।

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-এ এগুলির জন্য 1.7.0 বা তার পরের যেকোনও ভার্সন ব্যবহার করা হচ্ছে কিনা তা যাচাই করুন:

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

কম্পোনেন্ট ম্যাপিং

মাইগ্রেট করতে, আপনার ইমপোর্ট আপডেট করুন এবং কম্পোনেন্ট থেকে Tv প্রিফিক্স সরিয়ে দিন:

অননুমোদিত টিভি কম্পোনেন্ট Compose Foundation রিপ্লেসমেন্ট
TvLazyRow LazyRow
TvLazyColumn LazyColumn
TvLazyHorizontalGrid LazyHorizontalGrid
TvLazyVerticalGrid LazyVerticalGrid
pivotOffsets BringIntoViewSpec (via LocalBringIntoViewSpec)