我有这个覆盖视图,当按下按钮时,它应该通过调用视图模型中的函数来刷新视图。该代码确实适用于应用程序本身,但在预览中不起作用,我猜测这是因为环境变量不包含任何数据,因为它们低于输入数据的级别。在应用程序中,数据来自 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())
}
}
我在这里关注了另一篇文章,建议将环境对象放在预览下,但这不起作用。
好的,所以解决方案是在提供程序中手动完全设置环境对象。非常简单的解决方案,我只是没有思考清楚,但我现在明白了。
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
}() )
}
}