SwiftUI Lists

I have quite a bit of material about SwiftUI Lists. However, I seem to be lacking information about how to respond to an item being "selected". I put "selected" into quotes because my idea of selecting an item is different from putting a list into selection mode.

For example, in the book "SwiftUI for Masterminds" discusses in Chapter 10 about presenting a selection tool when a List is initialized with the selection attribute. The selection tool presents checkboxes (circles actually) that allow the user to select one or more items in the list. This type of selection is not what I am thinking about.

When I refer to selecting an item I mean tapping or clicking (on a Mac) an item. This action fires an event that the application responds to. This is not necessarily a navigation event. It might be that the appropriate response is send a message to a remote site or to perform a calculation using the item that was tapped or clicked. Thus, the complexity of navigation views need not come into play.

At the moment I don't have satisfactory answers for implementing this kind of behavior. I have found that I can an onTapGesture modifier to each item in the list. However, this seems like a convoluted approach. I really want the behavior to be at the level of the List. The tap or click would be associated with the List rather than with each item in the List.

As I learn more I will update this post. Please feel free to add additional information here. I would like to see this post be a useful resource for everyone.

Replies

Ideally a tap or click on an item should also cause the item to be highlighted.
Here is an experiment I did...
TextItem is the item I want to display in a list. For grins I gave it a property called tapped.
TextItemView is a View for presenting a TextItem.
Finally, there is TextListView for presenting the list of TextItemViews.
This code as written does display the list of items. And the onTapGesture is fired whenever an item is clicked. However, the background color of the TextItemView does not change. Why not? Because the view is not refreshed. I force a refresh of the view by changing the refresh state variable in TextListView. However, that has no effect. Why is this the case?

Turns out that the refresh state variable is not used in the body of the TextListView. If I simply add a Text struct to the VStack to display refresh, then the TextListView is updated whenever refresh is changed in the onTapGesture.

That said, this is not a satisfactory solution. I can click on items and change toggle their background color with each click. However, this needs to be coordinated with all the other items in the list. To do this I have to write code to turn off of the tapped state of each item and then set the selected items tapped state to true.

import SwiftUI

class TextItem: Identifiable {

    var id = UUID()
    var name: String = ""
    var tapped = false

    init(name: String) {
        self.name = name
    }
}



struct TextItemView: View {
    var item: TextItem

    var body: some View {
        Text("\(item.name)")
    }
}

struct TextListView: View {

    var Items: [TextItem] = []
    @State private var refresh = 0;

    var body: some View {

        VStack {

        List(Items) {item in
            if item.tapped {
                TextItemView(item: item)
                    .onTapGesture {
                        print("tap")
                        item.tapped.toggle()
                        self.refresh += 1
                    }.background(Color.blue)

            } else {
                TextItemView(item: item)
                    .onTapGesture {
                        print("tap")
                        item.tapped.toggle()
                        self.refresh += 1
                    }.background(Color.white)
            }
        }
    }
}