read

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

Image

@samwize

¯\_(ツ)_/¯

Back to Home