我正在制作一个视频应用程序,并尝试将数据从列表模式视图传递到父列表。 当我将静态 url 设置为 fetcher 时,列表视图可以工作。 我试图将 json url 从模态视图更改为父级并将数据解析为列表视图,当我在打印日志上看到但列表视图不更新内容时,获取器工作良好且正确。
VideoView.swift
public class VideoFetcher: ObservableObject {
@Published var videos = [Video]()
/*
init(){
load(videoURL: URL(string: "http://192.168.1.168:8080/category/shorts/vegie-elite.json")!)
}
*/
func load(videoURL: URL) {
URLSession.shared.dataTask(with: videoURL) {(data,response,error) in
do {
if let d = data {
let decodedLists = try JSONDecoder().decode([Video].self, from: d)
DispatchQueue.main.async {
self.videos = decodedLists
print(decodedLists)
}
}else {
print("No Data")
}
} catch {
print (error)
}
}.resume()
}
}
这是显示内容的列表
struct VideoView: View {
// @State private var isPresented = false
@State private var showingSheet = false
@ObservedObject var fetcher = VideoFetcher()
@State var vURL: String
var body: some View {
NavigationStack {
List (fetcher.videos) { video in
NavigationLink(destination: VideoPlayerLive(videoLink: video.v1080p)
.navigationBarBackButtonHidden(true)
.toolbar(.hidden, for: .tabBar)
) {
HStack {
WebImage(url: URL(string: video.image)) { image in
image.resizable() // Control layout like SwiftUI.AsyncImage, you must use this modifier or the view will use the image bitmap size
} placeholder: {
Rectangle().foregroundColor(Color("color.background.cell"))
}
// Supports options and context, like `.delayPlaceholder` to show placeholder only when error
.onSuccess { image, data, cacheType in
// Success
// Note: Data exist only when queried from disk cache or network. Use `.queryMemoryData` if you really need data
}
.indicator(.activity) // Activity Indicator
.transition(.fade(duration: 0.5)) // Fade Transition with duration
.scaledToFit()
.frame(width: 100, height: 100, alignment: .center)
.cornerRadius(5)
VStack (alignment: .leading) {
Spacer()
Text(video.name)
.font(.system(size: 18))
.foregroundColor(Color("color.text.orange"))
Spacer()
Text(video.released)
.font(.system(size: 13))
.foregroundColor(Color("color.text.gray"))
Spacer()
}
}
}
}
.refreshable {
fetcher.load(videoURL: URL(string: vURL)!)
fetcher.objectWillChange.send()
}
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
showingSheet.toggle()
}label: {
Image(systemName: "list.bullet")
}
.sheet(isPresented: $showingSheet) {
VideoCategory()
}
}
}
}
}
}
这是VideoModel.swift
public struct Video: Identifiable, Codable {
public var id: Int
public var name: String
public var image: String
public var released: String
public var v720p: String
public var v1080p: String
enum CodingKeys: String, CodingKey {
case id = "id"
case name = "title"
case image = "image"
case released = "year"
case v720p = "v720p"
case v1080p = "v1080p"
}
}
这是 VideoCategory(带列表的子视图)
var body: some View {
@State var fileItems = FileItem.preview()
NavigationStack {
List(fileItems, children: \.children) { fileItem in
if fileItem.isFolder {
Label(fileItem.title, systemImage: "folder.fill")
.foregroundColor(Color("color.text.pink"))
} else {
// Label(fileItem.title, systemImage: "film")
// .foregroundColor(Color("color.text.orange"))
Button {
// VideoFetcher().load(videoURL: URL(string: fileItem.url)!)
VideoView(vURL: fileItem.url).fetcher.load(videoURL: URL(string: fileItem.url)!)
self.presentationMode.wrappedValue.dismiss()
} label: {
HStack {
Image(systemName: "film")
Text(fileItem.title)
.foregroundColor(Color("color.text.orange"))
}
}
}
}
}
}
我尝试搜索解决方案,但找不到像我一样的案例。
谁能帮我解决这个问题。我是 swiftui 的新手。谢谢!
尝试这种方法来解决您的一些问题。 在您的
@StateObject private var fetcher = VideoFetcher()
中使用 VideoView
并使用 VideoCategory
将模型传递给 .environmentObject(fetcher)
。
查看此链接在应用程序中管理模型数据,它为您提供了一些有关如何在应用程序中管理数据的好示例。
由于代码中缺少许多元素,我无法测试代码, 然而,使用这种方法应该会让您更接近您想要实现的目标。
struct VideoCategory: View {
@EnvironmentObject var fetcher: VideoFetcher // <--- here
let fileItems = FileItem.preview() // <--- I assume this gives [FileItem]
var body: some View {
NavigationStack {
List(fileItems, children: \.children) { fileItem in
if fileItem.isFolder {
Label(fileItem.title, systemImage: "folder.fill")
.foregroundColor(Color("color.text.pink"))
} else {
// Label(fileItem.title, systemImage: "film")
// .foregroundColor(Color("color.text.orange"))
Button {
if let url = URL(string: fileItem.url) { // <--- here
fetcher.load(videoURL: url) // <--- here
}
} label: {
HStack {
Image(systemName: "film")
Text(fileItem.title)
.foregroundColor(Color("color.text.orange"))
}
}
}
}
}
}
}
struct VideoView: View {
@State private var showingSheet = false
@StateObject private var fetcher = VideoFetcher() // <--- here
let vURL: String // <--- here
var body: some View {
NavigationStack {
List (fetcher.videos) { video in
NavigationLink(destination: VideoPlayerLive(videoLink: video.v1080p)
.navigationBarBackButtonHidden(true)
.toolbar(.hidden, for: .tabBar)
) {
HStack {
// ......
}
}
}
.refreshable {
fetcher.load(videoURL: URL(string: vURL)!)
// fetcher.objectWillChange.send() // <--- should not have to do this
}
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
showingSheet.toggle()
}label: {
Image(systemName: "list.bullet")
}
.sheet(isPresented: $showingSheet) {
VideoCategory()
.environmentObject(fetcher) // <--- here
}
}
}
}
}
}