UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

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      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

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.