1

My app is movie app. There is a SingleMovieView to present one movie's related informations, like Director, Cast... And in the bottom, it is a scroll view to show the similar movies list. When user click one item of it, then should navigate to the selected movie view.

Well, the problem is actually it is same SingleMovieView for the destination. Or say that I want to reuse this view with different data for the selected movie. Currently, I'm using navigation link in ForEach of RecMovieList, and the taping is not working. So, how to do the self-invoke for the same View in SwiftUI?

enter image description here

Here is the code:

import SwiftUI
import KingfisherSwiftUI

struct SingleMovieView: View {

    var movieId: Int = -1

    @ObservedObject var model = MovieListViewModel()

    var body: some View {
        ScrollView(showsIndicators: false) {
            VStack(alignment: .leading)  {
                createPosterImage()
                MovieDetailView(movie: self.model.movie)

                if model.secSectionMoviesBundle.isEmpty {
                    Text("Loading")
                } else {
                    VStack(alignment: .leading, spacing: 12) {
                        CrewList(crews: (model.secSectionMoviesBundle[.Crew] as! [CrewViewModel]).filter {$0.job == "Director"} )
                        CastList(casts: model.secSectionMoviesBundle[.Cast] as! [CastViewModel])
                        ImageList(images: model.secSectionMoviesBundle[.Images] as! [ImageViewModel])
                        RecMovieList(movies: model.secSectionMoviesBundle[.Recomm] as! [MovieViewModel])
                    }
                }
            }
        }.edgesIgnoringSafeArea(.top)
        .onAppear() {
                self.model.getMovieDetail(id: self.movieId)
                self.model.getSecSectionMoviesBundle(id: self.movieId)
        }
    }

    // struct CrewList
    // struct CastList
    // struct ImageList


    struct RecMovieList: View {

        var movies: [MovieViewModel]

        var body: some View {
            VStack(alignment: .leading) {
                Text("\(SecHomeSection.Recomm.rawValue)")
                    .font(.headline)
                ScrollView(.horizontal) {
                    HStack(alignment: .top, spacing: 10) {
                        ForEach(0..<movies.count) { i in
                            VStack(alignment: .leading) {
                                NavigationLink(destination: SingleMovieView(movieId: self.movies[i].id)) {
                                    KFImage(source: .network(self.movies[i].posterUrl))
                                        .renderingMode(.original)
                                        .resizable()
                                        .frame(width: 100, height: 150)
                                        .aspectRatio(2/3, contentMode: .fill)
                                }

                                Text("\(self.movies[i].title)")
                                .lineLimit(2)
                                .foregroundColor(.gray)
                                    .frame(height: 50, alignment: .top)

                            }.frame(width: 100)
                        }
                    }
                }
                //.frame(height: 100)
            }
            .padding(.horizontal).padding(.bottom)
        }
    }

    fileprivate func createPosterImage() -> some View {
        return KFImage(source: .network(model.movie.posterUrl))
            .resizable().aspectRatio(contentMode: .fit)
    }
}

// Update:, as the comment, I realize this is the reloading data of current view instead of navigation. So I add the ObservedObject in struct RecMovieList too, then now the published model could be used in this struct too, to redo the networking request in onAppear().

And I change NavigationLink to Button as there is no navigation needed. Well, it works and the view could reload, but when I tap the movie list in the app, it triggered the touch event/reloading data, even for the dragging, swiping. How could I fix this thing? Use TapGesture?

struct RecMovieList: View {

        var movies: [MovieViewModel]
        @ObservedObject var model = MovieListViewModel()

        var body: some View {
            VStack(alignment: .leading) {
                Text("\(SecHomeSection.Recomm.rawValue)")
                    .font(.headline)
                ScrollView(.horizontal) {
                    HStack(alignment: .top, spacing: 10) {
                        ForEach(0..<movies.count) { i in
                            VStack(alignment: .leading) {
                                Button(action: {
                                    self.model.getMovieDetail(id: self.movies[i].id)
                                    self.model.getSecSectionMoviesBundle(id: self.movies[i].id)
                                }) {
                                    KFImage(source: .network(self.movies[i].posterUrl))
                                    .renderingMode(.original)
                                    .resizable()
                                    .frame(width: 100, height: 150)
                                    .aspectRatio(2/3, contentMode: .fill)
                                }



                                Text("\(self.movies[i].title)")
                                .lineLimit(2)
                                .foregroundColor(.gray)
                                    .frame(height: 50, alignment: .top)

                            }.frame(width: 100)
                        }
                    }
                }
                //.frame(height: 100)
            }
            .padding(.horizontal).padding(.bottom)
        }
    }
Zhou Haibo
  • 1,681
  • 1
  • 12
  • 32
  • Just from my view: you should change self.model.movie to the selected movie. As it is @Published (I think so) your view should get reloaded and updated with the new movie. – davidev Apr 07 '20 at 15:00
  • I realize it requires view reloading instead of navigation. This issue is fixed, please see the update in question. But I get another issue described in the update, may I ask your help again? – Zhou Haibo Apr 08 '20 at 04:24

1 Answers1

0

Try to cover navigationLink(){} with NavigationView{}

NavigationView {
  NavigationLink(destination: DestinationView()) { // code }
}

If it will not help, try also to cover entire "body"

 var body: some View { 
    NavigationView {
    //code
    }   
 }

UPDATE:

Try to use different from default button style for you recommendation button image

answer

.buttonStyle(BorderlessButtonStyle())
Mr.Fingers
  • 1,105
  • 1
  • 11
  • 15
  • Thanks for answer, I just realized what I need is reloading data of current view but not navigation as it is already in the same view. I had change the question title too, avoiding any misleading. – Zhou Haibo Apr 08 '20 at 04:46