বাতিল বা আপডেট করতে সোয়াইপ করুন

SwipeToDismissBox কম্পোনেন্ট ব্যবহারকারীকে বাঁদিকে বা ডানদিকে সোয়াইপ করে কোনও আইটেম বাতিল বা আপডেট করার অনুমতি দেয়।

API সারফেস

সোয়াইপ জেসচারের মাধ্যমে ট্রিগার করা অ্যাকশন প্রয়োগ করতে SwipeToDismissBox কম্পোজেবল ব্যবহার করুন। প্রধান প্যারামিটারের মধ্যে এগুলি পড়ে:

  • state: সোয়াইপ আইটেমে গণনা করে তৈরি করা ভ্যালু স্টোর করার জন্য SwipeToDismissBoxState স্টেট তৈরি করা হয়েছে, যা তৈরি হলে ইভেন্ট ট্রিগার করে।
  • backgroundContent: আইটেম কন্টেন্টের পিছনে দেখানো কাস্টমাইজ করার উপযুক্ত কম্পোজ করার আইটেম যা কন্টেন্ট সোয়াইপ করলে দেখা যায়।

প্রাথমিক উদাহরণ: সোয়াইপ করে আপডেট বা বাতিল করা

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

data class TodoItem(
    val itemDescription: String,
    var isItemDone: Boolean = false
)

@Composable
fun TodoListItem(
    todoItem: TodoItem,
    onToggleDone: (TodoItem) -> Unit,
    onRemove: (TodoItem) -> Unit,
    modifier: Modifier = Modifier,
) {
    val swipeToDismissBoxState = rememberSwipeToDismissBoxState(
        confirmValueChange = {
            if (it == StartToEnd) onToggleDone(todoItem)
            else if (it == EndToStart) onRemove(todoItem)
            // Reset item when toggling done status
            it != StartToEnd
        }
    )

    SwipeToDismissBox(
        state = swipeToDismissBoxState,
        modifier = modifier.fillMaxSize(),
        backgroundContent = {
            when (swipeToDismissBoxState.dismissDirection) {
                StartToEnd -> {
                    Icon(
                        painter = rememberVectorPainter(if (todoItem.isItemDone) AppIcons.CheckBox else AppIcons.CheckBoxOutlineBlank),
                        contentDescription = if (todoItem.isItemDone) "Done" else "Not done",
                        modifier = Modifier
                            .fillMaxSize()
                            .background(Color.Blue)
                            .wrapContentSize(Alignment.CenterStart)
                            .padding(12.dp),
                        tint = Color.White
                    )
                }
                EndToStart -> {
                    Icon(
                        painter = rememberVectorPainter(AppIcons.Delete),
                        contentDescription = "Remove item",
                        modifier = Modifier
                            .fillMaxSize()
                            .background(Color.Red)
                            .wrapContentSize(Alignment.CenterEnd)
                            .padding(12.dp),
                        tint = Color.White
                    )
                }
                Settled -> {}
            }
        }
    ) {
        ListItem(
            headlineContent = { Text(todoItem.itemDescription) },
            supportingContent = { Text("swipe me to update or remove.") }
        )
    }
}

কোড সম্পর্কে গুরুত্বপূর্ণ পয়েন্ট

  • swipeToDismissBoxState কম্পোনেন্টের স্ট্যাটাস ম্যানেজ করে। আইটেমের সাথে ইন্টার‍্যাকশন সম্পূর্ণ হয়ে গেলে এটি confirmValueChange কলব্যাক ট্রিগার করে। কলব্যাক বডি বিভিন্ন সম্ভাব্য অ্যাকশন ম্যানেজ করে। কলব্যাক একটি বুলিয়ান রিটার্ন করে যা কম্পোনেন্টকে জানায় যে এটি বাতিল করার অ্যানিমেশন দেখাবে কিনা। এই ক্ষেত্রে:
    • আইটেমটি শুরু থেকে শেষ পর্যন্ত সোয়াইপ করা হলে, এটি onToggleDone ল্যাম্বডাকে কল করে, বর্তমান todoItem পাস করে। এটি করণীয় আইটেম আপডেট করার সাথে সম্পর্কিত।
    • আইটেমটি শেষ থেকে শুরু পর্যন্ত সোয়াইপ করা হলে, এটি onRemove ল্যাম্বডাকে কল করে, বর্তমান todoItem পাস করে। এটি করার অর্থ হল, করণীয় তালিকা থেকে আইটেমটি মুছে ফেলা।
    • it != StartToEnd: সোয়াইপ করার দিক StartToEnd না হলে এই লাইন true রিটার্ন করে, অন্যথায় false রিটার্ন করে। false রিটার্ন করলে, "টগল করা হয়ে গেছে" সোয়াইপ করার পরে SwipeToDismissBox সাথে সাথে অদৃশ্য হয়ে যায় না, যার ফলে ভিজ্যুয়াল কনফার্মেশন বা অ্যানিমেশন দেখা যায়।
  • SwipeToDismissBox প্রতিটি আইটেমে অনুভূমিক সোয়াইপিং ইন্টার‍্যাকশন চালু করে। In rest, it shows the inner content of the component, but when a user starts swiping, the content is moved away and the backgroundContent appears. সাধারণ কন্টেন্ট এবং backgroundContent, উভয়ই নিজেদের রেন্ডার করার জন্য মূল কন্টেনারের সম্পূর্ণ সীমাবদ্ধতা পায়। content-এর উপরে backgroundContent আঁকা হয়েছে। এই ক্ষেত্রে:
    • backgroundContent-কে Icon হিসেবে প্রয়োগ করা হয়েছে, যার ব্যাকগ্রাউন্ডের রঙ SwipeToDismissBoxValue-এর উপর ভিত্তি করে তৈরি:
    • Blue StartToEnd সোয়াইপ করার সময় — করণীয় আইটেম টগল করা।
    • EndToStart সোয়াইপ করার সময় Red — করণীয় আইটেম মুছে দেওয়া।
    • Settled-এর জন্য ব্যাকগ্রাউন্ডে কিছু দেখানো হয় না — আইটেম সোয়াইপ না করা হলে, ব্যাকগ্রাউন্ডে কিছু দেখানো হয় না।
    • একইভাবে, যে Icon দেখানো হয় তা সোয়াইপ করার দিক অনুযায়ী পরিবর্তিত হয়:
    • StartToEnd-এ CheckBox আইকন দেখায় যখন করণীয় আইটেমটি সম্পূর্ণ হয়ে যায় এবং CheckBoxOutlineBlank আইকন দেখায় যখন এটি সম্পূর্ণ হয় না।
    • EndToStart-এ Delete আইকন দেখা যায়।

@Composable
fun SwipeItemExample() {
    val todoItems = remember {
        mutableStateListOf(
            TodoItem("Pay bills"), TodoItem("Buy groceries"),
            TodoItem("Go to gym"), TodoItem("Get dinner")
        )
    }

    LazyColumn {
        items(
            items = todoItems,
            key = { it.itemDescription }
        ) { todoItem ->
            TodoListItem(
                todoItem = todoItem,
                onToggleDone = { todoItem ->
                    todoItem.isItemDone = !todoItem.isItemDone
                },
                onRemove = { todoItem ->
                    todoItems -= todoItem
                },
                modifier = Modifier.animateItem()
            )
        }
    }
}

কোড সম্পর্কে গুরুত্বপূর্ণ পয়েন্ট

  • mutableStateListOf(...) একটি পর্যবেক্ষণযোগ্য তালিকা তৈরি করে যা TodoItem অবজেক্ট ধরে রাখতে পারে। এই তালিকা থেকে কোনও আইটেম যোগ বা সরানো হলে, Compose সেটির উপর নির্ভর করে UI-এর অংশগুলি আবার কম্পোজ করে।
    • mutableStateListOf()-এর মধ্যে, চারটি TodoItem অবজেক্ট তাদের নিজ নিজ বিবরণ সহ শুরু করা হয়: "বিল পেমেন্ট করুন", "মুদিখানা কিনুন", "জিমে যান" এবং "ডিনার করুন"।
  • LazyColumn-এ todoItems-এর উল্লম্বভাবে স্ক্রল করা যায় এমন তালিকা দেখা যায়।
  • ব্যবহারকারী কোনও অবজেক্টকে 'হয়ে গেছে' হিসেবে চিহ্নিত করলে, TodoListItem-এর মধ্যে থেকে onToggleDone = { todoItem -> ... } কলব্যাক ফাংশনটি কল করা হয়। এটি todoItem-এর isItemDone প্রপার্টি আপডেট করে। যেহেতু todoItems হল একটি mutableStateListOf, তাই এই পরিবর্তনটি একটি রিকম্পোজিশন ট্রিগার করে, UI আপডেট করে।
  • onRemove = { todoItem -> ... } হল একটি কলব্যাক ফাংশন যা ব্যবহারকারী আইটেমটি সরিয়ে দিলে ট্রিগার হয়। এটি todoItems তালিকা থেকে নির্দিষ্ট todoItem সরিয়ে দেয়। এর ফলে রিকম্পোজিশনও হয় এবং আইটেমটি দেখানো তালিকা থেকে সরিয়ে দেওয়া হবে।
  • প্রতিটি TodoListItem-এ একটি animateItem মডিফায়ার প্রয়োগ করা হয় যাতে আইটেমটি বাতিল করা হলে মডিফায়ারের placementSpec কল করা হয়। এটি আইটেমটি সরানোর পাশাপাশি তালিকার অন্যান্য আইটেমগুলিকে পুনরায় সাজানোর অ্যানিমেশন দেখায়।

ফলাফল

নিম্নলিখিত ভিডিওতে আগের স্নিপেট থেকে 'বাতিল করতে সোয়াইপ করুন' সংক্রান্ত প্রাথমিক কার্যকারিতা দেখানো হয়েছে:

ছবি ১। বাতিল করতে সোয়াইপ করার বেসিক প্রয়োগ যা কোনও আইটেমকে সম্পূর্ণ হিসেবে চিহ্নিত করতে এবং তালিকার কোনও আইটেমের জন্য বাতিল করার অ্যানিমেশন দেখাতে পারে।

সম্পূর্ণ স্যাম্পেল কোডের জন্য GitHub সোর্স ফাইল দেখুন।

উন্নত উদাহরণ: সোয়াইপ করার সময় ব্যাকগ্রাউন্ডের রঙ অ্যানিমেট করুন

নিম্নলিখিত স্নিপেট থেকে জানা যায় যে সোয়াইপ করার সময় কোনও আইটেমের ব্যাকগ্রাউন্ড কালার অ্যানিমেট করার জন্য কীভাবে পজিশনাল থ্রেশহোল্ড অন্তর্ভুক্ত করতে হয়।

data class TodoItem(
    val itemDescription: String,
    var isItemDone: Boolean = false
)

@Composable
fun TodoListItemWithAnimation(
    todoItem: TodoItem,
    onToggleDone: (TodoItem) -> Unit,
    onRemove: (TodoItem) -> Unit,
    modifier: Modifier = Modifier,
) {
    val swipeToDismissBoxState = rememberSwipeToDismissBoxState(
        confirmValueChange = {
            if (it == StartToEnd) onToggleDone(todoItem)
            else if (it == EndToStart) onRemove(todoItem)
            // Reset item when toggling done status
            it != StartToEnd
        }
    )

    SwipeToDismissBox(
        state = swipeToDismissBoxState,
        modifier = modifier.fillMaxSize(),
        backgroundContent = {
            when (swipeToDismissBoxState.dismissDirection) {
                StartToEnd -> {
                    Icon(
                        painter = rememberVectorPainter(if (todoItem.isItemDone) AppIcons.CheckBox else AppIcons.CheckBoxOutlineBlank),
                        contentDescription = if (todoItem.isItemDone) "Done" else "Not done",
                        modifier = Modifier
                            .fillMaxSize()
                            .drawBehind {
                                drawRect(lerp(Color.LightGray, Color.Blue, swipeToDismissBoxState.progress))
                            }
                            .wrapContentSize(Alignment.CenterStart)
                            .padding(12.dp),
                        tint = Color.White
                    )
                }
                EndToStart -> {
                    Icon(
                        painter = rememberVectorPainter(AppIcons.Delete),
                        contentDescription = "Remove item",
                        modifier = Modifier
                            .fillMaxSize()
                            .background(lerp(Color.LightGray, Color.Red, swipeToDismissBoxState.progress))
                            .wrapContentSize(Alignment.CenterEnd)
                            .padding(12.dp),
                        tint = Color.White
                    )
                }
                Settled -> {}
            }
        }
    ) {
        OutlinedCard(shape = RectangleShape) {
            ListItem(
                headlineContent = { Text(todoItem.itemDescription) },
                supportingContent = { Text("swipe me to update or remove.") }
            )
        }
    }
}

কোড সম্পর্কে গুরুত্বপূর্ণ পয়েন্ট

  • drawBehind সরাসরি Icon কম্পোজেবলের কন্টেন্টের পিছনে ক্যানভাসে আঁকে।
    • drawRect() ক্যানভাসে একটি আয়তক্ষেত্র আঁকে এবং নির্দিষ্ট Color দিয়ে ড্রয়িং স্কোপের সম্পূর্ণ বাউন্ডারি পূরণ করে।
  • সোয়াইপ করার সময়, আইটেমের ব্যাকগ্রাউন্ড কালার lerp ব্যবহার করে মসৃণভাবে ট্রানজিশন করে।
    • StartToEnd থেকে সোয়াইপ করার জন্য, ব্যাকগ্রাউন্ডের রঙ ধীরে ধীরে হালকা ধূসর থেকে নীল রঙে পরিবর্তিত হয়।
    • EndToStart থেকে সোয়াইপ করার জন্য, ব্যাকগ্রাউন্ডের রঙ ধীরে ধীরে হালকা ধূসর থেকে লাল রঙে পরিবর্তিত হয়।
    • একটি রঙ থেকে অন্য রঙে ট্রানজিশনের পরিমাণ swipeToDismissBoxState.progress দ্বারা নির্ধারিত হয়।
  • OutlinedCard তালিকার আইটেমগুলির মধ্যে একটি সূক্ষ্ম ভিজ্যুয়াল বিভাজন যোগ করে।

@Composable
private fun SwipeItemWithAnimationExample() {
    val todoItems = remember {
        mutableStateListOf(
            TodoItem("Pay bills"), TodoItem("Buy groceries"),
            TodoItem("Go to gym"), TodoItem("Get dinner")
        )
    }

    LazyColumn {
        items(
            items = todoItems,
            key = { it.itemDescription }
        ) { todoItem ->
            TodoListItemWithAnimation(
                todoItem = todoItem,
                onToggleDone = { todoItem ->
                    todoItem.isItemDone = !todoItem.isItemDone
                },
                onRemove = { todoItem ->
                    todoItems -= todoItem
                },
                modifier = Modifier.animateItem()
            )
        }
    }
}

কোড সম্পর্কে গুরুত্বপূর্ণ পয়েন্ট

  • এই কোড সম্পর্কে মূল পয়েন্টের জন্য, আগের বিভাগ থেকে মূল পয়েন্ট দেখুন, যা একই ধরনের কোড স্নিপেট বর্ণনা করে।

ফলাফল

নিম্নলিখিত ভিডিওতে অ্যানিমেটেড ব্যাকগ্রাউন্ড কালার সহ উন্নত কার্যকারিতা দেখানো হয়েছে:

ছবি ২। অ্যানিমেটেড ব্যাকগ্রাউন্ড কালার এবং অ্যাকশন রেজিস্টার করার আগে দীর্ঘ থ্রেশহোল্ড সহ, প্রকাশ বা মুছে ফেলার জন্য সোয়াইপ করার একটি বাস্তবায়ন।

সম্পূর্ণ স্যাম্পেল কোডের জন্য GitHub সোর্স ফাইল দেখুন।

অতিরিক্ত রিসোর্স