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

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(
                        if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.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(
                        imageVector = Icons.Default.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 lambda-কে কল করে, বর্তমান todoItem পাস করে। এটি টু-ডু আইটেম আপডেট করার সাথে সম্পর্কিত।
    • আইটেমটি শেষ থেকে শুরু পর্যন্ত সোয়াইপ করা হলে, এটি onRemove lambda-কে কল করে, বর্তমান todoItem পাস করে। এটি টাস্ক আইটেম মুছে ফেলার সাথে সম্পর্কিত।
    • it != StartToEnd: সোয়াইপ করার দিক true না হলে এই লাইনটি StartToEnd রিটার্ন করে এবং false অন্যথায়। "টগল করা হয়ে গেছে" সোয়াইপের পরে false SwipeToDismissBox সাথে সাথেই অদৃশ্য হয়ে যাওয়া আটকায়, যার ফলে ভিজ্যুয়াল কনফার্মেশন বা অ্যানিমেশন দেখা যায়।
  • SwipeToDismissBox প্রতিটি আইটেমে অনুভূমিক সোয়াইপ ইন্টার‍্যাকশন চালু করে। সাধারণ অবস্থায়, এটি কম্পোনেন্টের ভেতরের কন্টেন্ট দেখায়, কিন্তু ব্যবহারকারী যখন সোয়াইপ করা শুরু করেন, তখন কন্টেন্টটি সরে যায় এবং backgroundContent চিহ্নটি দেখা যায়। সাধারণ কন্টেন্ট ও backgroundContent, দুটিই প্যারেন্ট কন্টেনারের সম্পূর্ণ সীমাবদ্ধতা পায় যাতে সেগুলি নিজেদের রেন্ডার করতে পারে। backgroundContent-এর উপরে content আঁকা হয়েছে। এই ক্ষেত্রে:
    • backgroundContent-কে Icon হিসেবে প্রয়োগ করা হয়েছে, যার ব্যাকগ্রাউন্ড কালার SwipeToDismissBoxValue-এর উপর ভিত্তি করে তৈরি করা হয়েছে:
    • Blue সোয়াইপ করার সময় StartToEnd — করণীয় আইটেম টগল করা।
    • Red সোয়াইপ করার সময় EndToStart — কোনও 'করার কাজ' আইটেম মোছা।
    • Settled-এর জন্য ব্যাকগ্রাউন্ডে কিছু দেখানো হয় না — আইটেমটি সোয়াইপ করা না হলে, ব্যাকগ্রাউন্ডে কিছু দেখানো হয় না।
    • একইভাবে, Icon যেদিকে সোয়াইপ করা হবে সেই অনুযায়ী দেখানো হবে:
    • StartToEnd-এ CheckBox আইকন দেখানো হয় যখন করণীয় আইটেমটি সম্পূর্ণ হয়ে যায় এবং CheckBoxOutlineBlank আইকন দেখানো হয় যখন সেটি সম্পূর্ণ হয় না।
    • EndToStart একটি Delete আইকন দেখায়।

@Composable
private 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-এর উল্লম্বভাবে স্ক্রল করা যায় এমন তালিকা দেখানো হয়।
  • onToggleDone = { todoItem -> ... } হল একটি কলব্যাক ফাংশন যা ব্যবহারকারী কোনও অবজেক্ট সম্পূর্ণ করেছেন বলে চিহ্নিত করলে TodoListItem-এর মধ্যে থেকে ইনভোক করা হয়। এটি 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(
                        if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.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(
                        imageVector = Icons.Default.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 সোর্স ফাইল দেখুন।

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