为什么SwiftUI以相反的顺序加载项目?

时间:2020-04-27 20:29:27

标签: ios swift swiftui

我有一个由多个频道组成的流媒体应用程序,每个频道都有DVR。在主页上,所有频道均按照类别显示在行中。当用户单击某个频道项目时,它会转到一个详细页面,该页面在水平滚动行中包含DVR。所有通道和DVR项都有图像,我正在使用URLImage(https://github.com/dmytro-anokhin/url-image)库从URL加载图像。问题是当我运行该应用程序时,通道图像从右下到左上(从最后一项到第一项)加载。当我单击频道并导航到详细屏幕时,DVR的图像从右到左开始加载,即从最后一项到第一项。这就造成了一个问题,因为通道的DVR数据太多,并且加载所有图像需要5秒钟。如果它开始从第一项开始加载图像,那就太好了,因此即使花费5秒钟,用户也不会意识到并生效。

我不明白为什么这样做。有解决此问题的解决方案吗?我怎样才能迫使它从第一个项目开始加载到最后一个项目。这是我的代码,用于在其中显示DVR:

    ForEach(1..<chan.getDVR().count, id: \.self){index in

       Button(action:
       {
           self.str = self.chan.getDVR()[index].getHlsStreamURL()
           self.refresh = false
           self.ind = index

       }) {
            dvrItem(DVRItem: self.chan.getDVR()[index])
                .buttonStyle(PlainButtonStyle())
                .padding(.trailing,3)
                .cornerRadius(7)

       }.buttonStyle(PlainButtonStyle())             
    }

和dvrItem:

struct dvrItem: View {

        var DVRItem: dvr

        var body: some View {
             VStack( alignment: .leading) {
                URLImage(URL(string: DVRItem.getLogoUrlHD().replacingOccurrences(of: "http", with: "https", options: .literal, range: nil))!,  placeholder: { _ in Image("nologo").resizable().aspectRatio(contentMode: .fill).clipped() } ){
                    proxy in
                    proxy.image
                        .resizable()                     // Make image resizable
                        .aspectRatio(contentMode: .fill) // Fill the frame
                        .clipped()                       // Clip overlaping parts
                }
                .frame(width: 198, height: 114)
                .cornerRadius(7)
                .padding(.leading, 10)
                .padding(.top, 5)
                Text(self.DVRItem.getName())
                    .foregroundColor(Color.white)
                    .padding(.leading, 5)
                    .padding(.trailing, 5)

                Text(self.DVRItem.getDescription())
                    .foregroundColor(Color(red: 80.0/150, green: 80.0/150, blue: 80.0/150))
                    .lineLimit(nil)
                    .padding(.leading, 5)
                    .padding(.trailing, 5)
                Spacer()
                    .frame(height: 5)

            }
        }
    }

    struct dvrItem_Previews: PreviewProvider {
        static var previews: some View {
            dvrItem(DVRItem: channels[0].getDVR()[0])
        }
    }

我要怎么做?顺便说一下,我尝试仅加载前10个DVR项,例如ForEach(1..<10, id: \.self){index in,但它给运行时带来了错误。

1 个答案:

答案 0 :(得分:0)

尝试了许多事情后,我使用URLImage Library的选项解决了该问题。

URLImages具有一个延迟选项,可用于延迟图像加载过程。用法如下:

    URLImage(URL(string: DVRItem.getLogoUrlHD().replacingOccurrences(of: "http", with: "https", options: .literal, range: nil))!, delay: 0.25,  placeholder: { _ in Image("nologo").resizable().aspectRatio(contentMode: .fill).clipped() } ){
        proxy in
        proxy.image
            .resizable()                     // Make image resizable
            .aspectRatio(contentMode: .fill) // Fill the frame
            .clipped()                       // Clip overlaping parts
    }

我更新了DVRItem并添加了一个名为index的新变量:

    var ind: Int

并使用该变量无延迟地加载前5个元素,以0.15延迟加载后15个元素,并以0.25延迟加载其余元素。这样,它将立即加载前5个元素,然后加载其余元素。我的最终代码如下:

struct dvrItem: View {

    var DVRItem: dvr
    var ind: Int

    var body: some View {
         VStack( alignment: .leading) {
            URLImage(URL(string: DVRItem.getLogoUrlHD().replacingOccurrences(of: "http", with: "https", options: .literal, range: nil))!, delay: (self.ind < 5) ? 0 : (self.ind < 20 ? 0.15 : 0.25),  placeholder: { _ in Image("nologo").resizable().aspectRatio(contentMode: .fill).clipped() } ){
                proxy in
                proxy.image
                    .resizable()                     // Make image resizable
                    .aspectRatio(contentMode: .fill) // Fill the frame
                    .clipped()                       // Clip overlaping parts
            }
            .frame(width: 198, height: 114)
            .cornerRadius(7)
            .padding(.leading, 10)
            .padding(.top, 5)
            Text(self.DVRItem.getName())
                .foregroundColor(Color.white)
                .padding(.leading, 5)
                .padding(.trailing, 5)

            Text(self.DVRItem.getDescription())
                .foregroundColor(Color(red: 80.0/150, green: 80.0/150, blue: 80.0/150))
                .lineLimit(nil)
                .padding(.leading, 5)
                .padding(.trailing, 5)
            Spacer()
                .frame(height: 5)

        }
    }
}

struct dvrItem_Previews: PreviewProvider {
    static var previews: some View {
        dvrItem(DVRItem: channels[0].getDVR()[0], ind: 0)
    }
}

然后按如下所示调用DVRItem并为ind分配索引值:

ForEach(1..<chan.getDVR().count, id: \.self){index in

   Button(action:
   {
       self.str = self.chan.getDVR()[index].getHlsStreamURL()
       self.refresh = false
       self.ind = index

   }) {
        dvrItem(DVRItem: self.chan.getDVR()[index], ind: index)
            .buttonStyle(PlainButtonStyle())
            .padding(.trailing,3)
            .cornerRadius(7)

   }.buttonStyle(PlainButtonStyle())             
}

我仍然不知道为什么它从上一个项目开始加载,但这解决了我的问题。我尝试了类似本文In SwiftUI, where are the control events, i.e. scrollViewDidScroll to detect the bottom of list data的类似解决方案,但是它们不适用于水平滚动。