如何使用 ImageSlider 或类似的东西在 SwiftUI 中显示 Firebase 图像

How to show Firebase images in SwiftUI using an ImageSlider or something similar

一段时间以来我一直在尝试这样做,但未能实现我的目标。我想在 SwiftUI 的图像滑块或轮播中显示存储在 Firebase 中的图像。我能够获取并显示单个图像(那是另一回事)。但是,无法将图像从 firebase 加载到滑块。第一部分是获取 url 图像,但我不知道该怎么做。

更新

这会加载图像但不能自动滚动或自动迭代,图像一个接一个地加载而不是停止:

 func downImage(){
  
    let imageRef = Storage.storage()
    let loc = imageRef.reference().child("Images")
    loc.listAll{(result,error) in
        if error != nil{
            print("Ooops : ", error)
            return
        }
        
      
       for item in result!.items{
       let count = result?.items.count ?? 5 
       //provides actual count ie 3
       print("number of Images: ", self.count)
       print("images url : " , item)
            
            item.getData(maxSize: 15 * 1024 * 1024) { data, error in
                if let error = error {
                    print("\(error)")
                }
                guard let data = data else { return }
                
        DispatchQueue.main.async {
                  self.count = count
             //     self.actualImage.append(self.image)
                  self.image = UIImage(data: data as Data)!
                    
               }}}}}}

在滑块中,显示图像但在加载第三张图像后停止:

struct ImageSlider: View {

@StateObject var imageList = FireImageModel()
 
 /* private let timer = Timer.publish(every: 3, on: .main, in: .common) 
       .autoconnect() */


var body: some View {
   

    TabView(){

     /*   ForEach(imageList.actualImage, id: \.self) { item in
      if foreach loop is used with actualImage appending Images no 
      image is shown or Index out of range error */

                Image(uiImage: imageList.image)
                .resizable()
                .scaledToFill()
        }
        .tabViewStyle(PageTabViewStyle())
        .animation(.easeInOut(duration: 3))
        .onAppear(){
            imageList.downImage()
        }
    }

如果我将计时器(注释掉)与其他设置一起应用,它会不断更新所选图像 0、所选图像 1,但图像永远不会改变。需要图像在此滑块中自动滚动。

据我了解您的代码,您正在从 Firebase 下载字符串 url 到 @Published var imageURL: [String] = []。这不会下载 image 数据,只会下载 url 字符串。

在您的 loadImageURL 中,试试这个,将所有 url 字符串存储到您的 imageURL 数组中:

            DispatchQueue.main.async {
                if let linq = link {
                    self.imageURL.append(linq)
                    print("url link : ", self.imageURL)
                }
            

在你的 ImageSlider 中,使用类似这样的东西,而不是你的 Image(item):

  AsyncImage(url: URL(string: item))
                          

另外,将 @ObservedObject var imageList = FireImageModel() 更改为 @StateObject var imageList = FireImageModel()

并且,不要在代码中的任何地方使用 !,这会导致灾难。

编辑-1:

给定你的新代码,试试这个简单的示例代码,试着找出你的问题所在:

struct ImageSlider: View {
    @StateObject var imageList = FireImageModel()
    
    var body: some View {
        ScrollView {
            ForEach(imageList.actualImage, id: \.self) { item in
                Image(uiImage: item)
                    .resizable()
                    .frame(width: 222, height: 222)
            }
            .onAppear {
                imageList.downImage()
            }
        }
    }
}

另外,不要在代码中的任何地方使用 !

如果可行,试试这个:

struct ImageSlider: View {
    @StateObject var imageList = FireImageModel()
    
    var body: some View {
        VStack {
            if imageList.actualImage.count > 0 {
                TabView {
                    ForEach(imageList.actualImage, id: \.self) { item in
                        Image(uiImage: item)
                            .resizable()
                            .scaledToFill()
                    }
                }
                .tabViewStyle(PageTabViewStyle())
            } else {
                ProgressView()
            }
        }
        .onAppear {
            imageList.downImage()
        }
    }
}

您可能还想清理您的 FireImageModel,例如:

class FireImageModel: ObservableObject {
    @Published var actualImage: [UIImage] = []

    func downImage() {
        let imageRef = Storage.storage()
        let loc = imageRef.reference().child("Images")
        loc.listAll{(result,error) in
            if error != nil{
                print("Ooops : ", error)
                return
            }
            if let images = result {
                print("number of Images: ", images.items.count)
                for item in images.items {
                    print("images url : " , item)
                    item.getData(maxSize: 15 * 1024 * 1024) { data, error in
                        if let error = error {
                            print("\(error)")
                        }
                        DispatchQueue.main.async {
                            if let theData = data, let image = UIImage(data: theData) {
                                self.actualImage.append(image)
                            }
                        }
                    }
                }
            }
        }
    }
}

我能够在滑块中显示图像最终可能是自动迭代。当直接使用具有图像数据的数组时,ForEach 抛出索引超出范围错误(已知概率),因此@workingdogUkraine 的回答通过在进入 foreach 之前进行检查来帮助解决错误。自动迭代完成。查看 WorkingDog 更新的干净 FireImageModel 模型,下面是滑块结构:

 struct ImageSlider: View {

@StateObject var imageList = FireImageModel()
@State private var currentIndex = 0
@State var zoomed = false


private let timer = Timer.publish(every: 3, on: .main, in: .common) 
       .autoconnect()

var body: some View {
    // 2
    
    VStack {
    
              if imageList.actualImage.count > 0 {
                  GeometryReader{ proxy in
                      TabView(selection: $currentIndex){
                          ForEach(imageList.actualImage.indices, id: \.self) { 
                              item in
                              let sot = imageList.actualImage[item]
                              Image(uiImage: sot)
                              .resizable()
                              .scaledToFill()
                              .onTapGesture {
                                  self.zoomed.toggle()
                              }
                              .scaleEffect(self.zoomed ? 1.73 : 1)
                          }
                          .onReceive(timer, perform: {_ in
                              withAnimation(.spring(response: 1, 
                              dampingFraction: 1, blendDuration: 1)){
                            
                              currentIndex = currentIndex < 
                           imageList.actualImage.count ? currentIndex + 1 : 0
                          }
                        })
                  }
                  .tabViewStyle(PageTabViewStyle())
                  .frame(width: proxy.size.width, height: proxy.size.height/3)
                  
                 }
                  
                  
              }else {
                  ProgressView()
              }
    }.background(.ultraThinMaterial)
          .onAppear {
              imageList.downImage()
          }
         
      }}

图像出现不明显的动画 :),想添加一些很酷的动画,图像每 3 秒更改一次