2

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")
        }
    }
Philiong
  • 188
  • 1
  • 8

2 Answers2

2

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)
                }
        }
    }
}
Yonat
  • 4,382
  • 2
  • 28
  • 37
  • Hey @Yonat, thanks for your answer. I tried what you told me, but that takes me back to another error that i got earlier. ```Type '_' has no member 'id'``` The TrackPreviews do not conform to Identifiable, so i have to specify how to identify them with the ```id``` parameter. Also the TrackPreviews are part of an API Client that i use from my old internship, so i cant change or add the protokol to the model. I played around with making a copy of the model and using that, but that requires me to keep track of two arrays, since i need one for display and one for requests to the backend – Philiong Dec 20 '19 at 10:57
  • and also when i try to put in a hardcoded value i get this error: ```Value of type 'ListView' has no member 'playerSkipTo'``` – Philiong Dec 20 '19 at 13:24
  • What members does `TrackPreview` have? Can you use one of them to identify the track? For example: `var id: String { self.url.absoluteString }` – Yonat Dec 20 '19 at 13:35
  • As for missing `playerSkipTo`: First add that function, then you can call it. – Yonat Dec 20 '19 at 13:35
  • The ```TrackPreview``` has ```public let id: Int```. The ```playerSkipTo```method is in my ```PlaybackService``` , i will add it to the bottom of my question so you can see it. Again thanks for your time, i am really really stuck. – Philiong Dec 20 '19 at 16:00
0

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)
        }
Michel Storms
  • 336
  • 3
  • 10