স্ক্রোল, স্ক্রোল

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

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 { mutableStateOf(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 উপাদান যা আঙুলের চাপ সনাক্ত করে এবং এর জন্য সংখ্যাসূচক মান প্রদর্শন করে৷ আঙুল এর অবস্থান

নেস্টেড স্ক্রলিং

নেস্টেড স্ক্রোলিং এমন একটি সিস্টেম যেখানে একে অপরের মধ্যে থাকা একাধিক স্ক্রলিং উপাদান একটি একক স্ক্রোল অঙ্গভঙ্গিতে প্রতিক্রিয়া করে এবং তাদের স্ক্রলিং ডেল্টা (পরিবর্তন) যোগাযোগ করে একসাথে কাজ করে।

নেস্টেড স্ক্রোলিং সিস্টেম স্ক্রোলযোগ্য এবং শ্রেণিবদ্ধভাবে সংযুক্ত উপাদানগুলির মধ্যে সমন্বয়ের অনুমতি দেয় (বেশিরভাগ ক্ষেত্রে একই অভিভাবক ভাগ করে)। এই সিস্টেমটি স্ক্রলিং কন্টেনারগুলিকে লিঙ্ক করে এবং স্ক্রলিং ডেল্টার সাথে মিথস্ক্রিয়া করার অনুমতি দেয় যা প্রচারিত এবং ভাগ করা হচ্ছে।

কম্পোজ কম্পোজেবলের মধ্যে নেস্টেড স্ক্রলিং পরিচালনা করার একাধিক উপায় প্রদান করে। নেস্টেড স্ক্রলিংয়ের একটি সাধারণ উদাহরণ হল অন্য তালিকার ভিতরে একটি তালিকা, এবং আরও জটিল ক্ষেত্রে হল একটি ভেঙে যাওয়া টুলবার

স্বয়ংক্রিয় নেস্টেড স্ক্রোলিং

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

স্বয়ংক্রিয় নেস্টেড স্ক্রোলিং সমর্থিত এবং কম্পোজের কিছু উপাদান এবং সংশোধক দ্বারা বক্সের বাইরে সরবরাহ করা হয়: verticalScroll , horizontalScroll , scrollable , Lazy APIs এবং 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)
                    )
                }
            }
        }
    }
}

দুটি নেস্টেড উল্লম্ব স্ক্রোলিং UI উপাদান, ভিতরে অঙ্গভঙ্গি প্রতিক্রিয়া এবং ভিতরের বাইরে উপাদান

nestedScroll মডিফায়ার ব্যবহার করে

আপনি যদি একাধিক উপাদানের মধ্যে একটি উন্নত সমন্বিত স্ক্রোল তৈরি করতে চান, nestedScroll সংশোধক আপনাকে একটি নেস্টেড স্ক্রোলিং শ্রেণিবিন্যাস সংজ্ঞায়িত করে আরও নমনীয়তা দেয়। পূর্ববর্তী বিভাগে উল্লিখিত হিসাবে, কিছু উপাদান অন্তর্নির্মিত নেস্টেড স্ক্রোল সমর্থন আছে. যাইহোক, কম্পোজেবলের জন্য যেগুলি স্বয়ংক্রিয়ভাবে স্ক্রোলযোগ্য নয়, যেমন Box বা Column , এই জাতীয় উপাদানগুলিতে স্ক্রোল ডেল্টাগুলি নেস্টেড স্ক্রোল সিস্টেমে প্রচারিত হবে না এবং ডেল্টাগুলি NestedScrollConnection বা মূল উপাদানগুলিতে পৌঁছাবে না। এটি সমাধান করার জন্য, আপনি কাস্টম উপাদান সহ অন্যান্য উপাদানগুলিতে এই ধরনের সমর্থন প্রদান করতে nestedScroll ব্যবহার করতে পারেন।

নেস্টেড স্ক্রলিং চক্র

নেস্টেড স্ক্রোল চক্র হল স্ক্রোল ডেল্টার প্রবাহ যা নেস্টেড স্ক্রলিং সিস্টেমের অংশ, উদাহরণস্বরূপ স্ক্রোলযোগ্য উপাদান এবং মডিফায়ার, বা nestedScroll ব্যবহার করে সমস্ত উপাদান (বা নোড) এর মাধ্যমে হায়ারার্কি ট্রিতে উপরে এবং নীচে প্রেরণ করা হয়।

নেস্টেড স্ক্রলিং চক্রের পর্যায়গুলি

যখন একটি ট্রিগার ইভেন্ট (উদাহরণস্বরূপ, একটি অঙ্গভঙ্গি) একটি স্ক্রোলযোগ্য উপাদান দ্বারা সনাক্ত করা হয়, প্রকৃত স্ক্রলিং অ্যাকশনটি এমনকি ট্রিগার হওয়ার আগে, তৈরি করা ডেল্টাগুলি নেস্টেড স্ক্রোল সিস্টেমে পাঠানো হয় এবং তিনটি ধাপের মধ্য দিয়ে যায়: প্রি-স্ক্রোল, নোড ব্যবহার, এবং পোস্ট-স্ক্রোল।

নেস্টেড স্ক্রোলিং এর পর্যায়গুলি চক্র

প্রথম, প্রি-স্ক্রোল পর্বে, যে উপাদানটি ট্রিগার ইভেন্ট ডেল্টা পেয়েছে তারা সেই ইভেন্টগুলিকে, হায়ারার্কি ট্রির মাধ্যমে, শীর্ষস্থানীয় অভিভাবকের কাছে প্রেরণ করবে। ডেল্টা ইভেন্টগুলি তখন বুদবুদ হয়ে যাবে, যার অর্থ হল ডেল্টাগুলি মূল-সবচেয়ে অভিভাবক থেকে নীচের সন্তানের দিকে প্রচারিত হবে যেটি নেস্টেড স্ক্রোল চক্র শুরু করেছে।

প্রি-স্ক্রোল ফেজ - প্রেরণ আপ

এটি নেস্টেড স্ক্রোল পিতামাতাকে ( nestedScroll বা স্ক্রোলযোগ্য মডিফায়ার ব্যবহার করে কম্পোজেবল) নোড নিজেই এটি ব্যবহার করার আগে ডেল্টার সাথে কিছু করার সুযোগ দেয়।

প্রি-স্ক্রোল ফেজ - বুদবুদ নিচে

নোড খরচ পর্বে, নোড নিজেই তার পিতামাতার দ্বারা ব্যবহৃত ডেল্টা ব্যবহার করবে না। এটি যখন স্ক্রোলিং আন্দোলনটি আসলে সম্পন্ন হয় এবং দৃশ্যমান হয়।

নোড খরচ পর্যায়

এই পর্যায়ে, শিশু অবশিষ্ট স্ক্রোলের সমস্ত বা অংশ গ্রহণ করতে পারে। পোস্ট-স্ক্রোল পর্বের মধ্য দিয়ে যেতে যা কিছু অবশিষ্ট আছে তা ফেরত পাঠানো হবে।

পরিশেষে, পোস্ট-স্ক্রোল পর্বে, নোড নিজে ব্যবহার করেনি এমন কিছু আবার ব্যবহার করার জন্য তার পূর্বপুরুষদের কাছে পাঠানো হবে।

পোস্ট-স্ক্রোল পর্যায় - প্রেরণ আপ

স্ক্রোল-পরবর্তী পর্বটি প্রাক-স্ক্রোল পর্বের মতো একইভাবে কাজ করে, যেখানে পিতামাতাদের মধ্যে কেউ ব্যবহার করতে পারেন বা না করতে পারেন।

পোস্ট-স্ক্রোল পর্যায় - বুদবুদ নিচে

একইভাবে স্ক্রোল করার জন্য, যখন একটি টেনে নেওয়ার অঙ্গভঙ্গি শেষ হয়, ব্যবহারকারীর অভিপ্রায় একটি বেগে অনুবাদ করা যেতে পারে যা স্ক্রোলযোগ্য কন্টেইনারটি ফ্লিং (অ্যানিমেশন ব্যবহার করে স্ক্রোল) করতে ব্যবহৃত হয়। ফ্লিং নেস্টেড স্ক্রোল চক্রেরও অংশ, এবং ড্র্যাগ ইভেন্টের দ্বারা উত্পন্ন বেগ একই পর্যায়ে যায়: প্রি-ফ্লিং, নোড ব্যবহার এবং পোস্ট-ফ্লিং। মনে রাখবেন যে ফ্লিং অ্যানিমেশন শুধুমাত্র স্পর্শ অঙ্গভঙ্গির সাথে যুক্ত এবং অন্যান্য ইভেন্ট যেমন a11y বা হার্ডওয়্যার স্ক্রোল দ্বারা ট্রিগার করা হবে না।

নেস্টেড স্ক্রোলিং চক্রে অংশগ্রহণ করুন

চক্রে অংশগ্রহণের অর্থ হল শ্রেণীবিন্যাসের সাথে ব-দ্বীপের ব্যবহারকে বাধা দেওয়া, সেবন করা এবং রিপোর্ট করা। নেস্টেড স্ক্রোলিং সিস্টেম কীভাবে কাজ করে এবং কীভাবে এটির সাথে সরাসরি ইন্টারঅ্যাক্ট করতে হয় তা প্রভাবিত করার জন্য কম্পোজ টুলের একটি সেট সরবরাহ করে, উদাহরণস্বরূপ যখন একটি স্ক্রোলযোগ্য উপাদান এমনকি স্ক্রলিং শুরু করার আগে আপনাকে স্ক্রোল ডেল্টা দিয়ে কিছু করতে হবে।

যদি নেস্টেড স্ক্রোল চক্রটি নোডের একটি শৃঙ্খলে কাজ করে এমন একটি সিস্টেম হয়, তবে 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 মডিফায়ার ব্যবহার করে।
  • graphicsLayer মধ্যে translationY নিশ্চিত করে যে ছবিটি স্কেল করার সাথে সাথে উল্লম্বভাবে কেন্দ্রীভূত থাকে।

ফলাফল

পূর্ববর্তী স্নিপেটের ফলে স্ক্রলে একটি স্কেলিং ইমেজ প্রভাব দেখা যায়:

চিত্র 1 । স্ক্রলে একটি স্কেলিং ইমেজ ইফেক্ট।

নেস্টেড স্ক্রলিং ইন্টারপ

আপনি যখন স্ক্রোলযোগ্য কম্পোজেবলে স্ক্রোলযোগ্য View উপাদানগুলি নেস্ট করার চেষ্টা করেন, বা অন্য উপায়ে, আপনি সমস্যার সম্মুখীন হতে পারেন। সবচেয়ে বেশি লক্ষণীয় ঘটনা ঘটবে যখন আপনি শিশুটিকে স্ক্রোল করবেন এবং তার শুরু বা শেষ সীমানায় পৌঁছে যাবেন এবং পিতামাতার কাছ থেকে স্ক্রোল করার আশা করবেন। যাইহোক, এই প্রত্যাশিত আচরণ হয় না ঘটতে পারে বা প্রত্যাশিত হিসাবে কাজ করতে পারে না।

এই সমস্যাটি স্ক্রোলযোগ্য কম্পোজেবলে নির্মিত প্রত্যাশার ফলাফল। স্ক্রোলযোগ্য কম্পোজেবলগুলির একটি "নেস্টেড-স্ক্রোল-বাই-ডিফল্ট" নিয়ম রয়েছে, যার অর্থ হল যে কোনও স্ক্রোলযোগ্য ধারককে অবশ্যই নেস্টেড স্ক্রোল চেইনে অংশগ্রহণ করতে হবে, NestedScrollConnection মাধ্যমে অভিভাবক হিসাবে এবং NestedScrollDispatcher মাধ্যমে শিশু হিসাবে। শিশুটি তখন পিতামাতার জন্য একটি নেস্টেড স্ক্রোল চালাবে যখন শিশুটি আবদ্ধ হবে। উদাহরণ হিসাবে, এই নিয়মটি কম্পোজ Pager এবং কম্পোজ LazyRow একসাথে ভালভাবে কাজ করার অনুমতি দেয়। যাইহোক, যখন ViewPager2 বা RecyclerView এর সাথে ইন্টারঅপারেবিলিটি স্ক্রোলিং করা হচ্ছে, যেহেতু এগুলো NestedScrollingParent3 প্রয়োগ করে না, তাই সন্তান থেকে পিতামাতার কাছে ক্রমাগত স্ক্রোলিং সম্ভব নয়।

স্ক্রোলযোগ্য View উপাদান এবং স্ক্রোলযোগ্য কম্পোজেবলের মধ্যে নেস্টেড স্ক্রলিং ইন্টারপ API সক্ষম করতে, উভয় দিকে নেস্ট করা, আপনি নিম্নলিখিত পরিস্থিতিতে এই সমস্যাগুলি প্রশমিত করতে নেস্টেড স্ক্রোলিং ইন্টারপ API ব্যবহার করতে পারেন।

একটি শিশু ComposeView ধারণকারী একটি সহযোগী অভিভাবক View

একটি কোঅপারেটিং প্যারেন্ট View হল এমন একটি যা ইতিমধ্যেই NestedScrollingParent3 প্রয়োগ করে এবং তাই কোঅপারেটিং নেস্টেড চাইল্ড কম্পোজেবল থেকে স্ক্রলিং ডেল্টা পেতে সক্ষম। ComposeView এই ক্ষেত্রে একটি শিশু হিসাবে কাজ করবে এবং NestedScrollingChild3 বাস্তবায়ন করতে হবে (পরোক্ষভাবে)। একজন সহযোগী অভিভাবকের একটি উদাহরণ হল androidx.coordinatorlayout.widget.CoordinatorLayout

আপনার যদি স্ক্রোলযোগ্য View প্যারেন্ট কন্টেনার এবং নেস্টেড স্ক্রোলযোগ্য চাইল্ড কম্পোজেবলের মধ্যে নেস্টেড স্ক্রোলিং ইন্টারঅপারেবিলিটির প্রয়োজন হয়, তাহলে আপনি rememberNestedScrollInteropConnection() ব্যবহার করতে পারেন।

rememberNestedScrollInteropConnection() NestedScrollConnection অনুমতি দেয় এবং মনে রাখে যা একটি View প্যারেন্টের মধ্যে নেস্টেড স্ক্রোল আন্তঃঅপারেবিলিটি সক্ষম করে যা NestedScrollingParent3 এবং একটি রচনা শিশুকে প্রয়োগ করে। এটি একটি nestedScroll মডিফায়ারের সাথে ব্যবহার করা উচিত। যেহেতু কম্পোজ সাইডে ডিফল্টরূপে নেস্টেড স্ক্রলিং সক্ষম করা থাকে, আপনি View সাইডে নেস্টেড স্ক্রোল উভয়ই সক্ষম করতে এবং Views এবং কম্পোজেবলের মধ্যে প্রয়োজনীয় আঠালো যুক্তি যোগ করতে এই সংযোগটি ব্যবহার করতে পারেন।

একটি ঘন ঘন ব্যবহারের ক্ষেত্রে CoordinatorLayout , CollapsingToolbarLayout এবং একটি চাইল্ড কম্পোজেবল ব্যবহার করা হচ্ছে, এই উদাহরণে দেখানো হয়েছে:

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

আপনার অ্যাক্টিভিটি বা ফ্র্যাগমেন্টে, আপনাকে আপনার চাইল্ড কম্পোজযোগ্য এবং প্রয়োজনীয় 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-এর বাস্তবায়নকে কভার করে - যখন আপনার কাছে একটি শিশু AndroidView ধারণকারী প্যারেন্ট কম্পোজেবল থাকে। AndroidView NestedScrollDispatcher প্রয়োগ করে, যেহেতু এটি একটি কম্পোজ স্ক্রোলিং পিতামাতার কাছে একটি শিশু হিসাবে কাজ করে, সেইসাথে NestedScrollingParent3 কাজ করে, যেহেতু এটি একটি View স্ক্রোলিং শিশুর পিতামাতা হিসাবে কাজ করে৷ কম্পোজ প্যারেন্ট তারপর নেস্টেড স্ক্রোলযোগ্য চাইল্ড View থেকে নেস্টেড স্ক্রোল ডেল্টা পেতে সক্ষম হবেন।

নিচের উদাহরণটি দেখায় কিভাবে আপনি এই পরিস্থিতিতে নেস্টেড স্ক্রোলিং ইন্টারপ অর্জন করতে পারেন, একটি কম্পোজ কোলাপিং টুলবার সহ:

@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) {
            // ...
        }
    }
    // ...
}

এই উদাহরণটি দেখায় কিভাবে আপনি একটি scrollable সংশোধকের সাথে API ব্যবহার করতে পারেন:

@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 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 কম্পোজ লেভেল থেকে View লেভেলে ডেল্টা প্রেরণের জন্য দায়ী। এটি উপাদানটিকে নেস্টেড স্ক্রোলিংয়ে অংশগ্রহণ করতে সক্ষম করে, তবে এটি স্বয়ংক্রিয়ভাবে উপাদানগুলির স্ক্রলিং সক্ষম করে না। যে কম্পোজেবলগুলি স্বয়ংক্রিয়ভাবে স্ক্রোলযোগ্য নয়, যেমন Box বা Column , এই জাতীয় উপাদানগুলির স্ক্রোল ডেল্টাগুলি নেস্টেড স্ক্রোল সিস্টেমে প্রচারিত হবে না এবং ডেল্টাগুলি rememberNestedScrollInteropConnection() দ্বারা প্রদত্ত NestedScrollConnection পৌঁছাবে না, তাই সেই ডেল্টাগুলি হবে না প্যারেন্ট View কম্পোনেন্টে পৌঁছান। এটি সমাধান করতে, নিশ্চিত করুন যে আপনি এই ধরণের নেস্টেড কম্পোজেবলগুলিতে স্ক্রোলযোগ্য মডিফায়ার সেট করেছেন। আপনি আরও বিস্তারিত তথ্যের জন্য নেস্টেড স্ক্রোলিং- এর পূর্ববর্তী বিভাগটি উল্লেখ করতে পারেন।

একটি শিশু ComposeView ধারণকারী একটি অসহযোগী অভিভাবক View

একটি অ-সহযোগী দৃশ্য হল একটি যা View সাইডে প্রয়োজনীয় NestedScrolling ইন্টারফেসগুলি বাস্তবায়ন করে না। মনে রাখবেন যে এর অর্থ হল এই Views সাথে নেস্টেড স্ক্রোলিং আন্তঃকার্যযোগ্যতা বাক্সের বাইরে কাজ করে না। অসহযোগী Views হল RecyclerView এবং ViewPager2

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}