ios – How to handle animations of multiple Buttons on List row in SwiftUI?


I have a strange animation behavior when using multiple Buttons inside HStack inside List. First of all, I found information that I need to use some button style other than .automatic for both buttons to work properly in a single row. That seemed to work great, until I wanted to add animation to those buttons. I Want to create two buttons on each side of the row, but second one is shown only if condition is met, which can be achieved by clicking the first one. Simple example explaining that looks like that:

struct TestView: View {
    @State
    private var flag1 = true
    @State
    private var flag2 = false
    
    var body: some View {
        NavigationStack {
            List {
                HStack {
                    Button {
                        withAnimation {
                            flag1.toggle()
                        }
                    } label: {
                        Image(systemName: flag1 ? "checkmark.circle" : "circle")
                    }
                    Text("Some text")
                    if flag1 {
                        Spacer()
                        Button {
                            withAnimation {
                                flag2.toggle()
                            }
                        } label: {
                            Image(systemName: flag2 ? "checkmark.circle" : "circle")
                        }
                    }
                }
                .buttonStyle(.borderless)
            }
        }
    }
}

Code as above results in this strangely behaving animations:

Bad animation example

When I remove button style modifier (.buttonStyle(.borderless)) animations are better, yet still not ideal. There is animation for transition of second button when it’s supposed to hide, but it appears some times with animation and other times without it. Above all, it this situation both button actions are triggered simultaneously:

Good animation example

The best solution I found is to replace buttons with .onTapGesture modifiers:

struct TestView: View {
    @State
    private var flag1 = true
    @State
    private var flag2 = false

    var body: some View {
        NavigationStack {
            List {
                HStack {
                    Image(systemName: flag1 ? "checkmark.circle" : "circle")
                        .onTapGesture {
                            withAnimation {
                                flag1.toggle()
                            }
                        }
                    Text("Some text")
                    if flag1 {
                        Spacer()
                        Image(systemName: flag2 ? "checkmark.circle" : "circle")
                            .onTapGesture {
                                withAnimation {
                                    flag2.toggle()
                                }
                            }
                    }
                }
            }
        }
    }
}

Yet using those I loose on buttons formatting and animation of second button appearing is still working on random. So, here are my questions:

  • Is there a way to have 2 Buttons on one List row that doesn’t have problems with animations?
  • Why appearing transition animation for second button works on random (in cases when I use .buttonStyle(.borderless) or using .onTapGesture?
  • Do I loose much using .onTapGesture instead of Button and how can I format component in a way it looks like (and stay that way) normal Button?

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img