It is very easy to create swipe action for your rows. But there are SwiftUI nuances that might not show the buttons when you swipe. I hope this will save you some hours.
Do NOT apply button style
Let’s start with a working example:
List {
Text("Swipe this row from trailing edge")
.swipeActions {
Button("Reply", systemImage: "envelope.open") {}
}
}
If you were to apply any button style (eg. system borderless
or custom styles), then the button will NOT show up at all.
Button("Reply", systemImage: "envelope.open") {}
.buttonStyle(.borderless) // <-- This will cause a problem
This is because for swipe, the button MUST be automatic
style (the default).
SwiftUI made it easy to encounter this pitfall because you can apply a button style globally, or to any root view, and it will apply the same style to all children buttons. I know because I’ve spent hours to find one 🥲
If you have such global button style, then for swipe rows, you have to explicitly give it the automatic style.
Button("Reply", systemImage: "envelope.open") {}
.buttonStyle(.automatic) // <-- Explicit and overiding
How to show button text?
The example code above will show the reply button with image only, as the row doesn’t have sufficient height for the text.
If you increase the row height, the text will show.
These are SwiftUI predefined and automatic behaviour, for now.
Does not work for LazyVStack
It is common to use ScrollView
+ LazyVStack
instead of a List
.
Unfortunately, swipeActions
will only work with a List
.
You should use a List
, if possible, as the performance is better as it reuses the cells (backed by UICollectionView
).
If you still want to support swipe in a LazyVStack, then you might want to use some library, which apply drag gestures to your view.
How to customize
SwiftUI swipe action buttons have many limitations, and didn’t make it easy to customize. While you can use a Label
, you can’t do anything fancy with it. For example, if you try to add a background with gradient to an image, it will only show the image without the background!
Some things you can still do:
tint(.clear)
to remove the squarish tint fill- Use your custom
Image
to fill