WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

SOLVED: Selected List

Forums > SwiftUI

Good morning all,

I am trying to create a selectable list much like the iTunes Store app when you tap Genres in the nav bar at the top a sheet comes up that shows a list of Genres to select from and a checkmark to the right on the selected row. I am just at a loss on how to get the checkmark on the row.

List(selection: $selectedTopicData) {
    ForEach(listOfTopics, id: \.self) { topic in
        HStack {
            Text(topic.name)
                .textViewModifier(for: .body, weight: .regular, color: .primary)
            Spacer()
        }
        .contentShape(Rectangle())
        .onTapGesture {
            selectedTopicData = topic
            let _ = print("TopicData: \(String(describing: selectedTopicData))")
            dismiss()
        }
    }
}

If anyone has any ideas on how to add a checkmark that would be great.

Thanks Taz

2      

Hi, have you tried to add property to your topic var selected = false? Then in .onTapGesture you can switch it to be true. And as a result in your HStack you can check if that property is true and assign it a checkmark.

Something like that:

HStack {
            Text(topic.name)
                .textViewModifier(for: .body, weight: .regular, color: .primary)
            Spacer()
            if topic.selected {
              Image(systemName: "checkmark")
            }
        }

2      

I assume you mean a Menu Do this little project.

enum of the genres (including All), Note that it CaseIterable

enum Genre: String, CaseIterable {
    case all, house, jazz, rock
}

A Mock struct

struct Music: Identifiable {
    let id = UUID()
    let title: String
    let artist: String
    let genre: Genre
}

and now for View

struct ContentView: View {
    // MOCK DATA
    let allMusic = [
        Music(title: "Song 1", artist: "Artist 1", genre: .house),
        Music(title: "Song 2", artist: "Artist 1", genre: .house),
        Music(title: "Song 3", artist: "Artist 1", genre: .jazz),
        Music(title: "Song 4", artist: "Artist 2", genre: .jazz),
        Music(title: "Song 5", artist: "Artist 2", genre: .jazz),
        Music(title: "Song 6", artist: "Artist 2", genre: .rock),
        Music(title: "Song 7", artist: "Artist 3", genre: .rock),
        Music(title: "Song 8", artist: "Artist 3", genre: .rock),
        Music(title: "Song 8", artist: "Artist 3", genre: .rock),
    ]

    // A property to store the selected Genre
    @State private var selectedGenre = Genre.all

    // A computed property to filter the selected genre
    var filteredMusic: [Music] {
        if selectedGenre != .all {
            return allMusic.filter { $0.genre == selectedGenre }
        }

        return allMusic
    }

    var body: some View {
        NavigationStack {
            List {
                ForEach(filteredMusic) { music in
                    HStack {
                        VStack {
                            Text(music.title)
                                .font(.headline)
                            Text(music.artist)
                                .foregroundStyle(.secondary)
                        }

                        Spacer()

                        Text(music.genre.rawValue.capitalized)
                    }
                }
            }
            .navigationTitle("Music Library")
            .toolbar { // tool bar in navigation bar with a picker to select genre
                ToolbarItem {
                    Menu {
                        Picker("Genre", selection: $selectedGenre) {
                            ForEach(Genre.allCases, id: \.self) {
                                Text($0.rawValue.capitalized)
                            }
                        }
                    } label: {
                        Label("Genre", systemImage: "ellipsis.circle")
                    }
                }
            }
        }
    }
}

2      

@ygeras

Thanks so much for the reply. Sometimes the simplest solution is the hardest to figure out, LOL. At least for me, I tend to overthink the problem. So I did this using UserDefaults. I wanted a simple way to persist the choice if still on the tab. I ended up with this:

@AppStorage(StorageKeys.topicSelected.rawValue) var topicSelected = ""
List(selection: $selectedTopicData) {
    ForEach(listOfTopics, id: \.self) { topic in
        HStack {
            Text(topic.name)
                .textViewModifier(for: .body, weight: .regular, color: .primary)
            Spacer()
            if topic.name == topicSelected {
                Image(systemName: "checkmark")
                    .resizable()
                    .frame(width: 10, height: 10)
                    .foregroundColor(Color.accentColor)
                    .bold()
            }
        }
        .contentShape(Rectangle())
        .onTapGesture {
            selectedTopicData = topic
            topicSelected = topic.name
            dismiss()
        }
    }
}
.listStyle(.plain)

Anyway, thanks for your reply, Taz

2      

@NigelGee

Hey, my friend, I appreciate the reply. I'd thought about doing it in a Menu which would give me the checkmark automatically, but my list of topics is over a 100. So I didn't feel the menu was the right fit for a list that long. Plus, by putting this in a sheet I can give the user the ability to filter the topics with .searchable modifier.

Again my friend, thanks for great solution.

Taz

2      

Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.