Android Compose UI 清單互動

列表不僅僅是展示資料,還需要支援互動。最常見的就是側滑刪除 (Swipe to Dismiss)。

SwipeToDismissBox

Material 3 提供了 SwipeToDismissBox (舊版為 SwipeToDismiss) 來實作這個功能。

// 1. 定義滑動狀態
val dismissState = rememberSwipeToDismissBoxState(
    confirmValueChange = {
        if (it == SwipeToDismissBoxValue.EndToStart) {
            // 處理刪除邏輯
            viewModel.remove(item)
            true // 回傳 true 表示允許 dismiss 動畫繼續
        } else {
            false
        }
    }
)

SwipeToDismissBox(
    state = dismissState,
    backgroundContent = {
        // 2. 定義滑動時露出的背景 (例如紅色垃圾桶)
        val color = if (dismissState.dismissDirection == SwipeToDismissBoxValue.EndToStart) {
            Color.Red
        } else {
            Color.Transparent
        }
        
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(color)
                .padding(horizontal = 20.dp),
            contentAlignment = Alignment.CenterEnd
        ) {
            Icon(Icons.Default.Delete, contentDescription = null, tint = Color.White)
        }
    }
) {
    // 3. 主要內容 (列表項目)
    Card { ... }
}

列表動畫 (Item Animations)

LazyColumn 中,當項目被新增或移除時,我們希望能有動畫效果。在 Compose 中這非常簡單,只要在 items 中加上 Modifier.animateItem (注意:這是 Compose 1.7+ 的新 API,舊版需使用 ExperimentalFoundationApi 的 animateItemPlacement)。

LazyColumn {
    items(
        items = list,
        key = { it.id } // 必須提供 key
    ) { item ->
        Card(
            modifier = Modifier.animateItem() // 自動處理新增/刪除/移動動畫
        ) {
            Text(item.name)
        }
    }
}

Pull to Refresh (下拉更新)

使用 Material 3 的 PullToRefreshBox

val isRefreshing by viewModel.isRefreshing.collectAsStateWithLifecycle()
val state = rememberPullToRefreshState()

PullToRefreshBox(
    isRefreshing = isRefreshing,
    onRefresh = { viewModel.refresh() },
    state = state
) {
    LazyColumn { ... }
}

小結

透過 SwipeToDismissBoxPullToRefreshBox,我們可以為列表增添豐富的互動體驗,讓 App 手感更佳。