Problem passing value with SwiftUI List(), ForEach(), .onTapGesture WatchOS6

2.2k Views Asked by At

I am trying to use the .onTapGesture() to call a method on the tapped view and pass some kind of ID or any other form of identifier, but i dont know how to.

i have a view ListView that i create from data that i get from my array trackPreviewList: [TrackpreviewList].

The view looks like this:

struct ListView: View {
    @ObservedObject var model: PlaybackService
    @State var list = PlaybackService.sharedInstance.trackPreviewList

var body: some View {
        List {
            Section(header: Text("Songs")) {
                ForEach(model.trackPreviewList!, id: \.id) {
                    Text($0.artistName + ": " + $0.name)
                 }
                    .onDelete(perform: deleteTrack)
                    .onTapGesture(perform: skipTo)
            }
        }
    }

I am very new to SwiftUI and coding in general, but i think the right approach is to say cell(view?) 2 was tapped, therefore pass 2 to the method func playerSkipTo(skipToIndex: Int) I have tried to hardcode the value 2 like this and it works with the hardcoded value:

enter image description here

Though i am clueless when it comes to how to pass some kind of identifier, i think my problem is that i am trying to access the object outside of the scope where the method "knows about it". I have tried to use the $0.name variable just to see if i could pass anything but i get this error Contextual closure type '() -> Void' expects 0 arguments, but 1 was used in closure body which i think is because the .onTapGesture() method does not have a closure?.

I have tried to use the same logic as the .onDelete() method using IndexSet like this: enter image description here

The method that i want to pass the value to in the end looks like this:

func playerSkipTo(skipToIndex: Int) {
        if skipToIndex < ((trackPreviewList!.underestimatedCount)-1) {
            _ = firstly {
                TracklistProvider.sharedInstance.getPlaybackURL(trackPreview: trackPreviewList![skipToIndex])
            }.map { playbackoptions in
                self.createPlayerItemFromLink(assetURL: (playbackoptions?.playbackUrl)!)
            }.done{
                self.replacePlayerItem()
            }
        } else {
            print("The index \(skipToIndex) is out of bounds")
        }
    }

I am aware that i will need to change the playerSkipTo() method to take in IndexSet also, which i have also tried to play around with, trying to cast it to Int and such.

Any help or pointers are greatly appreciated!

Heres the playerSkipTo method:

        if skipToIndex < ((trackPreviewList!.underestimatedCount)-1) {
            _ = firstly {
                TracklistProvider.sharedInstance.getPlaybackURL(trackPreview: trackPreviewList![skipToIndex])
            }.map { playbackoptions in
                self.createPlayerItemFromLink(assetURL: (playbackoptions?.playbackUrl)!)
            }.done{
                self.replacePlayerItem()
            }
        } else {
            print("The index \(skipToIndex) is out of bounds")
        }
    }
2

There are 2 best solutions below

0
On

You can use a button on top of a ZStack:

        List{
            ForEach(appData.assets) { asset in
                ZStack {
                    HStack{
                        VStack(alignment: .leading) {
                            Text(asset.value)
                                .font(.headline)
                        }
                        Spacer()
                    }
                    Button(action: {assetPressed(id: asset.id)}, label: {
                        Text("")
                    })
                }
            }
            .onDelete(perform: deleteAsset)
        }
5
On

Instead of skipping to an index, skip to a specific track object:

func playerSkipTo(_ playbackoptions: PlaybackOptions) {
   // ...
}

Then change your View code to call this function on the Text instead of the ForEach:

List {
    Section(header: Text("Songs")) {
        ForEach(model.trackPreviewList!, id: \.id) {
            Text($0.artistName + ": " + $0.name)
                .onTapGesture {
                    self.playerSkipTo($0)
                }
        }
    }
}