Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用SwiftUI创建网格/UICollectionView_Ios_Swift_Swiftui - Fatal编程技术网

Ios 使用SwiftUI创建网格/UICollectionView

Ios 使用SwiftUI创建网格/UICollectionView,ios,swift,swiftui,Ios,Swift,Swiftui,我正在使用SwiftUI开发iOS应用程序。转到SwiftUI,我很快注意到缺少UICollectionView,这使得类似网格的视图很容易实现。我的手机项目代码如下: struct ListingView : View{ var body: some View{ VStack (alignment: .leading) { VStack{ HStack(spacing: 5){

我正在使用SwiftUI开发iOS应用程序。转到SwiftUI,我很快注意到缺少UICollectionView,这使得类似网格的视图很容易实现。我的手机项目代码如下:

struct ListingView : View{
   var body: some View{
        VStack (alignment: .leading) {
            VStack{
                HStack(spacing: 5){
                    KFImage(URL(string: Global.imageStoreListings + image1)!).resizable().scaledToFill()
                        .frame(height:140).frame(minWidth: 0, maxWidth: .infinity)
                    .cornerRadius(4)

                    KFImage(URL(string: Global.imageStoreListings + image2)!).resizable()
                        .scaledToFill()
                         .frame(height:140).frame(minWidth: 0, maxWidth: .infinity)
                         .cornerRadius(4)
                }.frame(minWidth: 0, maxWidth: .infinity)
                 HStack(spacing: 5){
                    KFImage(URL(string: Global.imageStoreListings + image3)!).resizable()
                     .scaledToFill()
                         .frame(height:140).frame(minWidth: 0, maxWidth: .infinity)
                        .cornerRadius(4)

                     KFImage(URL(string: Global.imageStoreListings + image4)!).resizable()
                        .scaledToFill()
                         .frame(height:140).frame(minWidth: 0, maxWidth: .infinity)
                        .cornerRadius(4)
                }.frame(minWidth: 0, maxWidth: .infinity)
            }.frame(minWidth: 0, maxWidth: .infinity)
            Text(listing.tags! + " • " + listing.location!).font(.custom("Nolasco Sans", size: 14))
            Text(listing.title).font(.custom("Google Sans", size: 16))

        }
       }
    }
我在ContentView中调用此选项:

  var body: some View{       
      List {
        ForEach(self.list, id: \.bid_id){ item in
                ListingView()
           }
       }
  }
结果如下所示(这是一行):

相反,我希望它看起来像这样(这是一行)


我已经尝试过嵌套循环,正如我从其他示例中看到的,但我对它非常着迷,所以我决定为我的特定场景寻求帮助。非常感谢您提供的任何帮助

解决此问题的方法是使用数据结构。您需要清单的2D数组

编辑:我正在使用数组转换器添加完整代码。我还没有调整风格,使其画面完美。但我认为一切都是可行的

import SwiftUI

struct ContentView: View {
    @ObservedObject var model = DataLoader()
    var body: some View {
        VStack {
            List {
                ForEach(self.model.data, id: \.self){ item in
                    HStack(spacing: 25) {
                        ForEach(item, id: \.self) { listing in
                            ListingView(listing: listing)
                        }
                    }
                }
            }
        }.padding()
    }
}

struct ListingView: View {
    @State var listing: Listing
    var body: some View {
        VStack (alignment: .leading) {
            VStack{
                HStack(spacing: 5){
                    Image(listing.images[0]).resizable().scaledToFill()
                        .frame(height:70).frame(minWidth: 0, maxWidth: .infinity)
                        .cornerRadius(4)

                    Image(listing.images[1]).resizable()
                        .scaledToFill()
                        .frame(height:70).frame(minWidth: 0, maxWidth: .infinity)
                        .cornerRadius(4)
                }.frame(minWidth: 0, maxWidth: .infinity)
                HStack(spacing: 5){
                    Image(listing.images[2]).resizable()
                        .scaledToFill()
                        .frame(height:70).frame(minWidth: 0, maxWidth: .infinity)
                        .cornerRadius(4)

                    Image(listing.images[3]).resizable()
                        .scaledToFill()
                        .frame(height:70).frame(minWidth: 0, maxWidth: .infinity)
                        .cornerRadius(4)
                }.frame(minWidth: 0, maxWidth: .infinity)
            }.frame(minWidth: 0, maxWidth: .infinity)
            Text(listing.tags + " • " + listing.location).font(.custom("Nolasco Sans", size: 14))
            Text(listing.title).font(.custom("Google Sans", size: 16))

        }
    }
}

struct Listing: Hashable, Decodable {
    var id: Int
    var title: String
    var location: String
    var tags: String
    var images: [String]
}

class DataLoader: ObservableObject {
    @Published var data: [[Listing]] = [[Listing]]()
    func loader() {
        if let url = URL(string: "https://nikz.in/data.json") {
            let req = URLRequest(url: url)
            URLSession.shared.dataTask(with: req) { data, res, err in
                if let data = data {
                    do {
                        let response = try JSONDecoder().decode([Listing].self, from: data)
                        DispatchQueue.main.async {
                            self.data = self.to2DArray(input: response, rows: 2)
                        }
                        return
                    } catch {
                        print("Unable to decode")
                    }
                } else {
                    print("Data not loading")
                }
            }.resume()
        }
    }

    func to2DArray<T>(input: [T], rows: Int) -> [[T]] {
        let columns = Int(ceil(Double(input.count)/Double(rows)))
        print(Double(input.count)/Double(rows))
        var output = [[T]]()
        for column in 0..<columns {
            var temp: [T] = [T]()
            for row in 0..<rows {
                let id = (column*rows)+row
                if id>input.count-1 { break }
                temp.append(input[id])
            }
            output.append(temp)
        }
        return output
    }

    init() {
        loader()
    }
}
导入快捷界面
结构ContentView:View{
@ObservedObject变量模型=数据加载器()
var body:一些观点{
VStack{
名单{
ForEach(self.model.data,id:\.self){item in
HStack(间距:25){
ForEach(item,id:\.self){正在
ListingView(列表:列表)
}
}
}
}
}.padding()
}
}
结构列表视图:视图{
@状态变量清单:清单
var body:一些观点{
VStack(对齐:。前导){
VStack{
HStack(间距:5){
Image(listing.images[0]).resizable().scaledToFill()
.frame(高度:70)。frame(最小宽度:0,最大宽度:。无穷大)
.转弯半径(4)
Image(清单.images[1]).resizeable()
.scaledToFill()
.frame(高度:70)。frame(最小宽度:0,最大宽度:。无穷大)
.转弯半径(4)
}.frame(最小宽度:0,最大宽度:无穷大)
HStack(间距:5){
Image(listing.images[2]).resizeable()
.scaledToFill()
.frame(高度:70)。frame(最小宽度:0,最大宽度:。无穷大)
.转弯半径(4)
Image(listing.images[3]).resizeable()
.scaledToFill()
.frame(高度:70)。frame(最小宽度:0,最大宽度:。无穷大)
.转弯半径(4)
}.frame(最小宽度:0,最大宽度:无穷大)
}.frame(最小宽度:0,最大宽度:无穷大)
文本(listing.tags+“•”+listing.location).font(.custom(“Nolasco Sans”,大小:14))
Text(listing.title).font(.custom(“googlesans”,大小:16))
}
}
}
结构列表:可散列,可解码{
变量id:Int
变量标题:字符串
变量位置:字符串
变量标记:字符串
变量图像:[字符串]
}
类数据加载器:ObserveObject{
@已发布的var数据:[[Listing]]=[[Listing]]()
func加载器(){
如果让url=url(字符串):https://nikz.in/data.json") {
let req=URLRequest(url:url)
URLSession.shared.dataTask(with:req){data,res,err in
如果let data=data{
做{
让response=try JSONDecoder().decode([Listing].self,from:data)
DispatchQueue.main.async{
self.data=self.to2DArray(输入:响应,行:2)
}
回来
}抓住{
打印(“无法解码”)
}
}否则{
打印(“数据未加载”)
}
}1.简历()
}
}
func to2DArray(输入:[T],行:Int)->[[T]]{
让columns=Int(ceil(Double(input.count)/Double(rows)))
打印(双精度(输入.计数)/双精度(行))
变量输出=[[T]]()

对于0中的列..感谢您的回复-但是考虑到我从API获取并拥有一个可解码的模型-我如何将其转换为上面建议的数组?@Niks Jon这太棒了,非常感谢,教会了我很多,并为我节省了很多时间headache@tendai其中有一个小的逻辑修正。
to2DArray()的第二个参数“rows”
实际上是指一行中的项目数,在您的情况下是2。是的@Nikz Jon,我注意到当我单击每一行时,NavigationLink会打开两个项目。它实际上是一个包含2个项目的行,单击它不会处理每个项目individually@tendai这就是列表视图的局限性。但是有一个解决方法可以使每个列表视图em作为按钮视图。