SwiftUI - 在环境对象中设置数据以进行预览的问题

问题描述 投票:0回答:1

我有这个覆盖视图,当按下按钮时,它应该通过调用视图模型中的函数来刷新视图。该代码确实适用于应用程序本身,但在预览中不起作用,我猜测这是因为环境变量不包含任何数据,因为它们低于输入数据的级别。在应用程序中,数据来自 FeedView 并传递给子级。

视图结构为FeedView -> ReaderView -> ReaderOverlay。当在 FeedView 预览上按下按钮时,它可以正常工作,但在 ReaderView 或 ReaderOverlay 中无法正常工作。

这是 ReaderView 的代码:

struct ReaderView: View {

@State var chapter:  ChapterInfo

@StateObject private var reader = ReaderViewModel()
@EnvironmentObject var mangaFeed: FeedViewModel
@EnvironmentObject var ch: ChapterIndex

@State private var isTapped = false
@State private var selected: Int = 0 //used in tabview
@State var currentPage = 1
@State var totalPages = 0


var body: some View {
    
    TabView(selection: $selected){
            ForEach(Array(reader.pages.enumerated()), id: \.element) { index, element in
                Page(page: element)
                    .tag(index)
                    .onChange(of: selected){ val in
                        currentPage = val + 1 //tracks changes in selected tab to display page numbers
                    }
                    
            }
        }
        .tabViewStyle(.page(indexDisplayMode: PageTabViewStyle.IndexDisplayMode.never))
        .onTapGesture(){
            isTapped.toggle() // when this is tapped the overlay for control will be toggled
        }
        .overlay(alignment: .top){
            if isTapped{
                readerOverlay(chapter: chapter, currentPage: $currentPage, totalPages: reader.pages.count)
                    .environmentObject(reader)
                
            }
        }
        .task{
            await reader.populate(chapterID: chapter.id)
        }
    
}

    
}

ReaderOverlay 及其预览的代码如下:

struct readerOverlay: View {


@State var nextChapter: ChapterInfo?

@State var chapter: ChapterInfo
@EnvironmentObject var mangaFeed: FeedViewModel
@EnvironmentObject var reader: ReaderViewModel
@EnvironmentObject var ch: ChapterIndex



@Binding var currentPage: Int
@State var totalPages: Int

@Environment(\.dismiss) var dismiss

var body: some View {
    
    
    VStack{
        
        //the proxy inherits the size of the parent view which in this case is just the screen
        GeometryReader{ proxy in
            RoundedRectangle(cornerRadius: 15)
                .overlay(
                    HStack{
                        VStack(alignment: .leading){
                            
                            //Displays name of the manga
                            Text(chapter.relationships.first{
                                $0.type == "manga"
                            }?.attributes?.title["en"] ?? "")
                            .font(.headline)
                            .fontWeight(.medium)
                            .foregroundColor(.white)
                                .lineLimit(1)
                                
                            //Displays name of the chapter
                            Text("Ch \(chapter.attributes.chapter ?? "") - \(chapter.attributes.title ?? "")" ).font(.caption2)
                                .fontWeight(.light)
                                .foregroundColor(.white)
                                .lineLimit(1)
                            
                        }
                        
                        Spacer()
                        
                        //Dismisses panel window
                        Button(action: {
                            dismiss()
                        }){
                            Image(systemName: "xmark")
                                .foregroundColor(.red)
                        }
                        
                        
                       
                    }.frame(width: proxy.size.width - 100)
                        
                        
                        
                ).padding(.horizontal, 30.0)
                .frame(width: proxy.size.width , height: 60)
                .foregroundColor(.black)
                
        }
        
        HStack{
            Text("\(currentPage) / \(totalPages)")
            
            //The button that refreshes the reader view
            Button(action: {
                
                nextChapter = mangaFeed.items[ch.chIndex + 1]
                ch.chIndex += 1
                Task {await reader.populate(chapterID: nextChapter!.id)}
                
            }){
                Text("next chapter")
            }
            
        }
        
    }
    
    
}
}

struct readerOverlay_Previews: PreviewProvider {

@State static var currPage = 0
static var previews: some View {
    
    let dummy =  ChapterInfo(id: "5df4596c-febd-492e-bf0d-d98f59fd3f2b", type: "Chapter", attributes: chInfo_Attributes(volume: "1", chapter: "1", title: "Test", publishAt: "2020-05-23", externalUrl: "" ), relationships: [chapter_Relationships(id: "s", type: "manga", attributes: attributes(title: ["en":"20TH Century Boys"]))])
    
    
    readerOverlay(chapter: dummy, currentPage: $currPage, totalPages: 10)
        .environmentObject(FeedViewModel())
        .environmentObject(ChapterIndex())
        .environmentObject(ReaderViewModel())
    
}
}

我在这里关注了另一篇文章,建议将环境对象放在预览下,但这不起作用。

swift swiftui mocking swiftui-previews
1个回答
0
投票

好的,所以解决方案是在提供程序中手动完全设置环境对象。非常简单的解决方案,我只是没有思考清楚,但我现在明白了。

ReaderView预览代码:

struct Reader_Previews: PreviewProvider {
    
    
    static var previews: some View {
        
        
        let dummy =  ChapterInfo(id: "5df4596c-febd-492e-bf0d-d98f59fd3f2b", type: "chapter", attributes: chInfo_Attributes(volume: "1", chapter: "1", title: "Friend", publishAt: "2020-05-23", externalUrl: "" ), relationships: [chapter_Relationships(id: "s", type: "manga", attributes: attributes(title: ["en":"20th Century Boys"]))])
                
        let mangaID = "ad06790a-01e3-400c-a449-0ec152d6756a"
        
        //providing the preview with mock environment objects for FVM and CI class
        ReaderView(chapterID: dummy.id)
            .environmentObject({ () -> FeedViewModel in
                let envObj = FeedViewModel()
                Task{await envObj.populate(mangaID:mangaID)}
                return envObj
            }() )
            .environmentObject({ () -> ChapterIndex in
                let envObj = ChapterIndex()
                envObj.chIndex = 0
                return envObj
            }() )
        
    }
}

和 ReaderOverlay

struct readerOverlay_Previews: PreviewProvider {
    
    @State static var currPage = 0
    @State static var selected = 0
    
    
    
    static var previews: some View {
        
      
        let dummy =  ChapterInfo(id: "5df4596c-febd-492e-bf0d-d98f59fd3f2b", type: "chapter", attributes: chInfo_Attributes(volume: "1", chapter: "1", title: "Friend", publishAt: "2020-05-23", externalUrl: "" ), relationships: [chapter_Relationships(id: "s", type: "manga", attributes: attributes(title: ["en":"20th Century Boys"]))])
        
        let mangaID = "ad06790a-01e3-400c-a449-0ec152d6756a"
        
        //providing the preview provider mock environment objects
        readerOverlay(currentPage: $currPage, selected: $selected, totalPages: 10)
            .environmentObject({ () -> FeedViewModel in
                let envObj = FeedViewModel()
                Task{await envObj.populate(mangaID:mangaID)}
                return envObj
            }() )
            .environmentObject({ () -> ReaderViewModel in
                let envObj = ReaderViewModel()
                Task{await envObj.populate(chapterID: dummy.id)}
                return envObj
            }() )
            .environmentObject({ () -> ChapterIndex in
                let envObj = ChapterIndex()
                envObj.chIndex = 0
                return envObj
            }() )
        
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.