• Software
  • Blog
  • About
Menu

Dabbling Badger

Street Address
54455
Phone Number

Your Custom Text Here

Dabbling Badger

  • Software
  • Blog
  • About

A Quick Fix For Misbehaving List Cells In SwiftUI

November 19, 2020 Jonathan Badger
Photo by Donald Giannatti on Unsplash

Photo by Donald Giannatti on Unsplash

One of the most frustrating aspects of working with SwiftUI is trying to debug unexpected behavior. I recently ran into a noodle-scratcher while adding search and interactivity features to views inside of a List. Here, I will briefly show you a few unexpected behaviors you might run into when working with a List view that has NavigationLinks and provide you with a simple fix!

Adding a button to a cell that has a navigation link.

If you try and add a button to a cell that has a navigation link you will notice that the button is essentially ignored and anywhere you tap on the cell pushes the linked view onto the stack. To demonstrate, here is a snippet of code with a list of X-Men:

struct NavigableListWithButton: View {
    private let xmen = ["Wolverine","Cyclops", "Storm", "Rogue", "Iceman", "Beast", "Professor X"]
    @State var currentFavorite = ""
    var body: some View {
        NavigationView {
            List {
                ForEach(xmen, id:\.self) { teamMember in
                    NavigationLink(destination: Text(teamMember)) {
                        HStack {
                            Button(action: {currentFavorite = teamMember}, label: {
                                Image(systemName: (teamMember == currentFavorite ?  "heart.fill" : "heart"))
                                    .foregroundColor(.pink)
                            })
                            Text(teamMember)
                        }
                    }  
                }
            }
            .navigationBarTitle("The X-Men", displayMode: .automatic)
        }
    }
}

I have added a heart button to allow the user to select their favorite, but sadly things are not working as expected.

NavigationListWithButton.gif

This behavior also partially manifests in views without navigation links. For example, if we add a view to the top of the list that has a sort button the entire view will become tappable and enact the function of the button.

SortButtonBehavior.gif

The Solution

Every Button in SwiftUI has a style that dictates its behavior and appearance. If you don’t set the style explicitly using the buttonStyle modifier SwiftUI will pick an appropriate style based on the platform and context. Apple mentions this briefly in their documentation on DefaultButtonStyle, but doesn’t provide information on which styles are chosen when. In this case, leaving the behavior up to SwiftUI seems to be causing the problem. If you set the style of your buttons explicitly, as in:

Button(action: {
    currentFavorite = teamMember
}, label: {
    Image(systemName: (teamMember == currentFavorite ?  "heart.fill" : "heart"))
    .foregroundColor(.pink)
})
.buttonStyle(PlainButtonStyle())

things will work as you originally intended. As a side note, it doesn’t actually appear to matter what button style you choose, so long as you don’t let SwiftUI decide for you. I hope you have found this short post helpful. So which X-man is your favorite?

In Programming Tags SwiftUI, Debugging
← Overlapping Navigation Titles In SwiftUIDismissing The Keyboard In SwiftUI 2.0 →

E-mail: dabblingbadger@gmail.com

Copyright © 2023 Dabbling Badger LLC

POWERED BY SQUARESPACE