স্ক্রল মডিফায়ার

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))
        }
    }
}

স্ক্রল করা যায় এমন এরিয়া মডিফায়ার

scrollableArea মডিফায়ার হল কাস্টম স্ক্রল করা যায় এমন কন্টেনার তৈরি করার জন্য একটি মৌলিক বিল্ডিং ব্লক। এটি scrollable মডিফায়ারের উপর উচ্চ-স্তরের অ্যাবস্ট্রাকশন প্রদান করে, যা জেসচার ডেল্টা ইন্টারপ্রিটেশন, কন্টেন্ট ক্লিপিং এবং ওভারস্ক্রল এফেক্টের মতো সাধারণ প্রয়োজনীয়তাগুলি ম্যানেজ করে।

কাস্টম ইমপ্লিমেন্টেশনের জন্য scrollableArea ব্যবহার করা হলেও, স্ট্যান্ডার্ড স্ক্রলিং তালিকার জন্য সাধারণত verticalScroll, horizontalScroll-এর মতো রেডিমেড সমাধান অথবা LazyColumn-এর মতো কম্পোজেবল ব্যবহার করা উচিত। এই উচ্চ-স্তরের কম্পোনেন্টগুলি সাধারণ ব্যবহারের ক্ষেত্রে সহজ এবং সেগুলি নিজেই scrollableArea ব্যবহার করে তৈরি করা হয়।

scrollableArea এবং scrollable মডিফায়ারের মধ্যে পার্থক্য

scrollableArea এবং scrollable-এর মধ্যে প্রধান পার্থক্য হল, ব্যবহারকারীর স্ক্রল করার জেসচার তারা কীভাবে ব্যাখ্যা করে:

  • scrollable (র ডেল্টা): ডেল্টা সরাসরি স্ক্রিনে ব্যবহারকারীর ইনপুটের (যেমন, পয়েন্টার টেনে আনা) ফিজিক্যাল মুভমেন্ট দেখায়।
  • scrollableArea (কন্টেন্ট-ওরিয়েন্টেড ডেল্টা): delta-কে শব্দার্থগতভাবে উল্টে দেওয়া হয় যাতে স্ক্রল পজিশনে বেছে নেওয়া পরিবর্তনকে এমনভাবে দেখানো যায় যাতে মনে হয় কন্টেন্ট ব্যবহারকারীর জেসচারের সাথে সাথে সরছে, যা সাধারণত পয়েন্টার মুভমেন্টের বিপরীত হয়।

বিষয়টি এইভাবে ভাবুন: scrollable আপনাকে বলে যে পয়েন্টার কীভাবে সরানো হয়েছে, যেখানে scrollableArea সেই পয়েন্টার সরানোর বিষয়টি অনুবাদ করে যাতে বোঝা যায় যে কন্টেন্ট কীভাবে একটি সাধারণ স্ক্রলযোগ্য ভিউয়ের মধ্যে সরানো উচিত। এই ইনভার্সনের কারণেই স্ট্যান্ডার্ড স্ক্রল করা যায় এমন কন্টেনার প্রয়োগ করার সময় scrollableArea আরও স্বাভাবিক বলে মনে হয়।

নিচের সারণীতে সাধারণ পরিস্থিতির জন্য ডেল্টা চিহ্নের সারসংক্ষেপ দেওয়া হল:

ইউজার জেসচার

dispatchRawDelta-এ scrollable-এর দ্বারা ডেল্টা রিপোর্ট করা হয়েছে

scrollableArea-এর মাধ্যমে dispatchRawDelta-এ ডেল্টা রিপোর্ট করা হয়েছে*

পয়েন্টার উপরের দিকে সরান

নেতিবাচক

ইতিবাচক

পয়েন্টার নিচের দিকে সরান

ইতিবাচক

নেগেটিভ

পয়েন্টার বাঁদিকে সরবে

নেতিবাচক

পজিটিভ (RTL-এর জন্য নেগেটিভ)

পয়েন্টার ডানদিকে সরান

ইতিবাচক

নেগেটিভ (RTL-এর জন্য পজিটিভ)

(*) scrollableArea ডেল্টা চিহ্নের ব্যাপারে নোট: scrollableArea-এর ডেল্টা চিহ্নটি শুধু একটি সাধারণ ইনভার্সন নয়। এটি বুদ্ধিমত্তার সাথে বিবেচনা করে:

  1. ওরিয়েন্টেশন: উল্লম্ব বা অনুভূমিক।
  2. LayoutDirection: LTR বা RTL (বিশেষ করে অনুভূমিক স্ক্রোলিংয়ের জন্য গুরুত্বপূর্ণ)।
  3. reverseScrolling ফ্ল্যাগ: স্ক্রল করার দিক উল্টে দেওয়া হয়েছে কিনা।

স্ক্রল ডেল্টা ইনভার্ট করার পাশাপাশি, scrollableArea লেআউটের বাউন্ডে কন্টেন্ট ক্লিপ করে এবং ওভারস্ক্রল এফেক্টের রেন্ডারিং ম্যানেজ করে। ডিফল্ট হিসেবে, এটি LocalOverscrollFactory-এর দেওয়া এফেক্ট ব্যবহার করে। আপনি scrollableArea ওভারলোড ব্যবহার করে এটি কাস্টমাইজ বা বন্ধ করতে পারবেন যা OverscrollEffect প্যারামিটার গ্রহণ করে।

scrollableArea মডিফায়ার কখন ব্যবহার করতে হবে

horizontalScroll বা verticalScroll মডিফায়ার বা লেজি লেআউট দ্বারা পর্যাপ্তভাবে পরিবেশিত হয় না এমন কাস্টম স্ক্রলিং কম্পোনেন্ট তৈরি করার প্রয়োজন হলে, আপনাকে scrollableArea মডিফায়ার ব্যবহার করতে হবে। এতে প্রায়শই এমন কেস থাকে যেখানে:

  • কাস্টম লেআউট লজিক: স্ক্রল পজিশনের উপর ভিত্তি করে আইটেমের বিন্যাস ডায়নামিকভাবে পরিবর্তন হলে।
  • অনন্য ভিজ্যুয়াল এফেক্ট: বাচ্চারা স্ক্রল করার সময় ট্রান্সফর্মেশন, স্কেলিং বা অন্যান্য এফেক্ট প্রয়োগ করা।
  • verticalScroll বা লেজি লেআউট যা দেখায় তার বাইরে স্ক্রলিং মেকানিক্সের উপর সূক্ষ্ম কন্ট্রোল প্রয়োজন হলে সরাসরি কন্ট্রোল ব্যবহার করুন।

scrollableArea ব্যবহার করে কাস্টম চাকার মতো তালিকা তৈরি করুন

নিম্নলিখিত স্যাম্পেলটি scrollableArea ব্যবহার করে একটি কাস্টম উল্লম্ব তালিকা তৈরি করার পদ্ধতি দেখায়, যেখানে আইটেমগুলি কেন্দ্র থেকে দূরে সরে যাওয়ার সাথে সাথে ছোট হয়ে যায়, যা একটি "চাকার মতো" ভিজ্যুয়াল এফেক্ট তৈরি করে। এই ধরনের স্ক্রল-নির্ভর ট্রান্সফর্মেশন হল scrollableArea-এর জন্য একটি নিখুঁত ব্যবহারিক প্রয়োগ।

ছবি ২. scrollableArea ব্যবহার করে কাস্টমাইজ করা উল্লম্ব তালিকা।

@Composable
private fun ScrollableAreaSample() {
    // ...
    Layout(
        modifier =
            Modifier
                .size(150.dp)
                .scrollableArea(scrollState, Orientation.Vertical)
                .background(Color.LightGray),
        // ...
    ) { measurables, constraints ->
        // ...
        // Update the maximum scroll value to not scroll beyond limits and stop when scroll
        // reaches the end.
        scrollState.maxValue = (totalHeight - viewportHeight).coerceAtLeast(0)

        // Position the children within the layout.
        layout(constraints.maxWidth, viewportHeight) {
            // The current vertical scroll position, in pixels.
            val scrollY = scrollState.value
            val viewportCenterY = scrollY + viewportHeight / 2

            var placeableLayoutPositionY = 0
            placeables.forEach { placeable ->
                // This sample applies a scaling effect to items based on their distance
                // from the center, creating a wheel-like effect.
                // ...
                // Place the item horizontally centered with a layer transformation for
                // scaling to achieve wheel-like effect.
                placeable.placeRelativeWithLayer(
                    x = constraints.maxWidth / 2 - placeable.width / 2,
                    // Offset y by the scroll position to make placeable visible in the viewport.
                    y = placeableLayoutPositionY - scrollY,
                ) {
                    scaleX = scaleFactor
                    scaleY = scaleFactor
                }
                // Move to the next item's vertical position.
                placeableLayoutPositionY += placeable.height
            }
        }
    }
}
// ...

স্ক্রল করা যায় এমন মডিফায়ার

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())
    }
}

একটি UI এলিমেন্ট আঙুলের প্রেস শনাক্ত করছে এবং আঙুলের লোকেশনের জন্য সংখ্যাসূচক মান দেখাচ্ছে
ছবি ৩. একটি UI এলিমেন্ট আঙুলের প্রেস শনাক্ত করছে এবং আঙুলের লোকেশনের জন্য সংখ্যাসূচক মান দেখাচ্ছে।