1+ package com.example.compose.snippets.components
2+
3+ import androidx.compose.animation.animateColorAsState
4+ import androidx.compose.foundation.background
5+ import androidx.compose.foundation.layout.Arrangement
6+ import androidx.compose.foundation.layout.Row
7+ import androidx.compose.foundation.layout.Spacer
8+ import androidx.compose.foundation.layout.fillMaxSize
9+ import androidx.compose.foundation.layout.padding
10+ import androidx.compose.foundation.lazy.LazyColumn
11+ import androidx.compose.foundation.lazy.items
12+ import androidx.compose.material.icons.Icons
13+ import androidx.compose.material.icons.filled.CheckBox
14+ import androidx.compose.material.icons.filled.CheckBoxOutlineBlank
15+ import androidx.compose.material.icons.filled.Delete
16+ import androidx.compose.material3.Icon
17+ import androidx.compose.material3.ListItem
18+ import androidx.compose.material3.OutlinedCard
19+ import androidx.compose.material3.SwipeToDismissBox
20+ import androidx.compose.material3.SwipeToDismissBoxValue
21+ import androidx.compose.material3.Text
22+ import androidx.compose.material3.rememberSwipeToDismissBoxState
23+ import androidx.compose.runtime.Composable
24+ import androidx.compose.runtime.getValue
25+ import androidx.compose.runtime.mutableStateListOf
26+ import androidx.compose.runtime.remember
27+ import androidx.compose.ui.Alignment
28+ import androidx.compose.ui.Modifier
29+ import androidx.compose.ui.graphics.Color
30+ import androidx.compose.ui.graphics.RectangleShape
31+ import androidx.compose.ui.graphics.lerp
32+ import androidx.compose.ui.tooling.preview.Preview
33+ import androidx.compose.ui.unit.dp
34+
35+ // [START android_compose_components_todoitem]
36+ data class TodoItem (
37+ var isItemDone : Boolean ,
38+ var itemDescription : String
39+ )
40+ // [END android_compose_components_todoitem]
41+
42+ // [START android_compose_components_swipeitem]
43+ @Composable
44+ fun SwipeItem (
45+ value : TodoItem ,
46+ startToEndAction : (TodoItem ) -> Unit ,
47+ endToStartAction : (TodoItem ) -> Unit ,
48+ modifier : Modifier = Modifier ,
49+ content : @Composable (TodoItem ) -> Unit
50+ ) {
51+ val swipeToDismissBoxState = rememberSwipeToDismissBoxState(
52+ confirmValueChange = {
53+ when (it) {
54+ SwipeToDismissBoxValue .StartToEnd -> {
55+ startToEndAction(value)
56+ // Do not dismiss this item.
57+ false
58+ }
59+ SwipeToDismissBoxValue .EndToStart -> {
60+ endToStartAction(value)
61+ true
62+ }
63+ SwipeToDismissBoxValue .Settled -> {
64+ false
65+ }
66+ }
67+ }
68+ )
69+
70+ SwipeToDismissBox (
71+ state = swipeToDismissBoxState,
72+ modifier = modifier
73+ .fillMaxSize(),
74+ backgroundContent = {
75+ Row (
76+ modifier = Modifier
77+ .background(
78+ when (swipeToDismissBoxState.dismissDirection) {
79+ SwipeToDismissBoxValue .StartToEnd -> {
80+ Color .Blue
81+ }
82+ SwipeToDismissBoxValue .EndToStart -> {
83+ Color .Red
84+ }
85+ SwipeToDismissBoxValue .Settled -> {
86+ Color .LightGray
87+ }
88+ }
89+ )
90+ .fillMaxSize(),
91+ verticalAlignment = Alignment .CenterVertically ,
92+ horizontalArrangement = Arrangement .SpaceBetween
93+ ) {
94+ when (swipeToDismissBoxState.dismissDirection) {
95+ SwipeToDismissBoxValue .StartToEnd -> {
96+ if (value.isItemDone) {
97+ Icon (
98+ imageVector = Icons .Default .CheckBox ,
99+ contentDescription = " Item done" ,
100+ tint = Color .White ,
101+ modifier = Modifier
102+ .padding(12 .dp)
103+ )
104+ } else {
105+ Icon (
106+ imageVector = Icons .Default .CheckBoxOutlineBlank ,
107+ contentDescription = " Item not done" ,
108+ tint = Color .White ,
109+ modifier = Modifier
110+ .padding(12 .dp)
111+ )
112+ }
113+ }
114+
115+ SwipeToDismissBoxValue .EndToStart -> {
116+ Spacer (modifier = Modifier )
117+ Icon (
118+ imageVector = Icons .Default .Delete ,
119+ contentDescription = " Remove item" ,
120+ tint = Color .White ,
121+ modifier = Modifier
122+ .padding(12 .dp)
123+ )
124+ }
125+
126+ SwipeToDismissBoxValue .Settled -> {}
127+ }
128+ }
129+ }
130+ ) {
131+ content(value)
132+ }
133+ }
134+ // [END android_compose_components_swipeitem]
135+
136+ @Preview(showBackground = true )
137+ // [START android_compose_components_swipeitemexample]
138+ @Composable
139+ private fun SwipeItemExample () {
140+ val todoItems = remember {
141+ mutableStateListOf(
142+ TodoItem (isItemDone = false , itemDescription = " Pay bills" ),
143+ TodoItem (isItemDone = false , itemDescription = " Buy groceries" ),
144+ TodoItem (isItemDone = false , itemDescription = " Go to gym" ),
145+ TodoItem (isItemDone = false , itemDescription = " Get dinner" )
146+ )
147+ }
148+
149+ LazyColumn {
150+ items(
151+ items = todoItems,
152+ key = { it.itemDescription }
153+ ) { todoItem ->
154+ SwipeItem (
155+ value = todoItem,
156+ startToEndAction = {
157+ todoItem.isItemDone = ! todoItem.isItemDone
158+ },
159+ endToStartAction = {
160+ todoItems - = todoItem
161+ }
162+ ) {
163+ ListItem (
164+ headlineContent = { Text (text = todoItem.itemDescription) },
165+ supportingContent = { Text (text = " swipe me to update or remove." ) }
166+ )
167+ }
168+ }
169+ }
170+ }
171+ // [END android_compose_components_swipeitemexample]
172+
173+ // [START android_compose_components_swipecarditem]
174+ @Composable
175+ fun SwipeCardItem (
176+ value : TodoItem ,
177+ startToEndAction : (TodoItem ) -> Unit ,
178+ endToStartAction : (TodoItem ) -> Unit ,
179+ modifier : Modifier = Modifier ,
180+ content : @Composable (TodoItem ) -> Unit
181+ ) {
182+ val swipeToDismissState = rememberSwipeToDismissBoxState(
183+ positionalThreshold = { totalDistance -> totalDistance * 0.25f },
184+ confirmValueChange = {
185+ when (it) {
186+ SwipeToDismissBoxValue .StartToEnd -> {
187+ startToEndAction(value)
188+ // Do not dismiss this item.
189+ false
190+ }
191+ SwipeToDismissBoxValue .EndToStart -> {
192+ endToStartAction(value)
193+ true
194+ }
195+ SwipeToDismissBoxValue .Settled -> {
196+ false
197+ }
198+ }
199+ }
200+ )
201+
202+ SwipeToDismissBox (
203+ modifier = Modifier ,
204+ state = swipeToDismissState,
205+ backgroundContent = {
206+ // Cross-fade the background color as the drag gesture progresses.
207+ val color by animateColorAsState(
208+ when (swipeToDismissState.targetValue) {
209+ SwipeToDismissBoxValue .Settled -> Color .LightGray
210+ SwipeToDismissBoxValue .StartToEnd ->
211+ lerp(Color .LightGray , Color .Blue , swipeToDismissState.progress)
212+
213+
214+ SwipeToDismissBoxValue .EndToStart ->
215+ lerp(Color .LightGray , Color .Red , swipeToDismissState.progress)
216+ }, label = " swipeable card item background color"
217+ )
218+ Row (
219+ modifier = Modifier
220+ .background(color)
221+ .fillMaxSize(),
222+ verticalAlignment = Alignment .CenterVertically ,
223+ horizontalArrangement = Arrangement .SpaceBetween
224+ ) {
225+ when (swipeToDismissState.dismissDirection) {
226+ SwipeToDismissBoxValue .StartToEnd -> {
227+ if (value.isItemDone) {
228+ Icon (
229+ imageVector = Icons .Default .CheckBox ,
230+ contentDescription = " Item done" ,
231+ tint = Color .White ,
232+ modifier = Modifier
233+ .padding(12 .dp)
234+ )
235+ } else {
236+ Icon (
237+ imageVector = Icons .Default .CheckBoxOutlineBlank ,
238+ contentDescription = " Item not done" ,
239+ tint = Color .White ,
240+ modifier = Modifier
241+ .padding(12 .dp)
242+ )
243+ }
244+ }
245+
246+
247+ SwipeToDismissBoxValue .EndToStart -> {
248+ Spacer (modifier = Modifier )
249+ Icon (
250+ imageVector = Icons .Default .Delete ,
251+ contentDescription = " Remove item" ,
252+ tint = Color .White ,
253+ modifier = Modifier
254+ .padding(12 .dp)
255+ )
256+ }
257+
258+
259+ SwipeToDismissBoxValue .Settled -> {}
260+ }
261+ }
262+ }) {
263+ content(value)
264+ }
265+ }
266+ // [END android_compose_components_swipecarditem]
267+
268+ // [START android_compose_components_swipecarditemexample]
269+ @Preview
270+ @Composable
271+ private fun SwipeCardItemExample () {
272+ val todoItems = remember {
273+ mutableStateListOf(
274+ TodoItem (isItemDone = false , itemDescription = " Pay bills" ),
275+ TodoItem (isItemDone = false , itemDescription = " Buy groceries" ),
276+ TodoItem (isItemDone = false , itemDescription = " Go to gym" ),
277+ TodoItem (isItemDone = false , itemDescription = " Get dinner" )
278+ )
279+ }
280+
281+ LazyColumn {
282+ items(
283+ items = todoItems,
284+ key = { it.itemDescription }
285+ ) { todoItem ->
286+ SwipeCardItem (
287+ value = todoItem,
288+ startToEndAction = {
289+ todoItem.isItemDone = ! todoItem.isItemDone
290+ },
291+ endToStartAction = {
292+ todoItems - = todoItem
293+ }
294+ ) {
295+ OutlinedCard (shape = RectangleShape ) {
296+ ListItem (
297+ headlineContent = { Text (todoItem.itemDescription) },
298+ supportingContent = { Text (" swipe me to update or remove." ) })
299+ }
300+ }
301+ }
302+ }
303+ }
304+ // [END android_compose_components_swipecarditemexample]
0 commit comments