SwiftUI 列表行布局

Posted

技术标签:

【中文标题】SwiftUI 列表行布局【英文标题】:SwiftUI list row layout 【发布时间】:2020-05-16 08:16:44 【问题描述】:

回到几个 SwiftUI 布局问题:

我正在尝试将 2 个列表与自定义单元格并排显示。 我创建了单元格视图 (EventRow.swift) 并将它们显示在我的内容视图中。

为了更好的可见性,我在列表中添加了边框。

从下图可以看出,结果惨不忍睹:

我希望将渐变效果应用于整个单元格,包括宽度和高度。 我尝试设置 EventRow 的框架(使用 .infinity 作为宽度和高度),但这会使应用程序崩溃。 由于 EventRow 的大小是推断出来的,我也不知道如何调整行单元格的高度以适应它的大小:您可以看到水平分隔条不适合我的自定义 EventRow...

如果有人对此有一些建议,将不胜感激。

示例项目可以在here找到

但我也在下面发布了我的代码:

内容视图:

import SwiftUI

struct ContentView: View 

    struct listsSetup: ViewModifier 
      func body(content: Content) -> some View 
        return content
        .frame(maxHeight: UIScreen.main.bounds.size.height/3)
        .overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.blue, lineWidth: 1))
            .padding([.top, .bottom])
        
    

    var body: some View 

        VStack 
                HStack 
                    VStack  // 1 list Vstack
                        VStack 
                        Text("List 1")
                            .padding(.top)
                        List 
                            EventRow()
                            EventRow()
                         // END of 1st List
                        
                            .modifier(listsSetup())
                     // END of 1st list VStack

                    VStack  // 2nd Vstack
                        VStack 
                        Text("List 2")
                            .padding(.top)
                        List 
                            EventRow()
                            EventRow()
                         // END of Landings List
                        
                        .modifier(listsSetup())
                     // End of 2nd List VStack
                 // End of 1st & 2nd lists HStack
                    .padding(.top)
                Spacer()
         // END of VStack
     // END of body



struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
    ContentView()
    

事件行:

import SwiftUI

struct EventRow: View 

    var body: some View 
        LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom)
        .edgesIgnoringSafeArea(.all)
        .overlay(
            VStack
            HStack 
            Text("Text one")
                Spacer()
            Text("Text two")
            
                HStack 
                    Spacer()
                    Image(systemName: "flame")
                    .font(.body)
                    Spacer()
                 // END of second HStack
                    .padding(.top, -14)
             //END of Vstack
        )
    


struct EventRow_Previews: PreviewProvider 
    static var previews: some View 
       EventRow().previewLayout(.fixed(width: 300, height: 60))

    

尝试 Asperi 的解决方案后进行编辑: 我实际的 EventRow 代码如下,listRowBackground 修饰符似乎没有任何作用:

import SwiftUI
import CoreData

struct EventRow: View 

    var event: Events

    var dateFormatter: DateFormatter 
     let formatter = DateFormatter()
    // formatter.dateStyle = .long
     formatter.dateFormat = "dd MMM yy"
     return formatter
     

    var body: some View 
    VStack
            HStack 
            Text(event.airportName ?? "")
                .font(.headline)
                Spacer()
            Text(self.dateFormatter.string(from: event.eventDate!))
                .font(.body)
            
                HStack 
                    Text(event.flightNumber ?? "")
                        .font(.body)
                    Spacer()
                    if event.isSimulator 
                        Image(systemName: "s.circle")
                            .font(.body)
                     else 
                        Image(systemName: "airplane")
                        .font(.body
                        )
                    
                    Spacer()
                    if event.aircraftType == 0 
                        Text("")
                        .font(.body)
                     else if event.aircraftType == 1 
                        Text("330")
                        .font(.body)
                     else if event.aircraftType == 2 
                        Text("350")
                        .font(.body)
                    
                 // END of second HStack
                    .padding(.top, -14)

         //END of Vstack
                .listRowBackground(LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom))

    


struct EventRow_Previews: PreviewProvider 
    static var previews: some View 
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

                let newEvent = Events(context: context)
                newEvent.eventDate = Date()
                newEvent.aircraftType = 1
                newEvent.airportName = "LDG tst"
                newEvent.flightNumber = "AF TEST"
                newEvent.id = UUID()
                newEvent.isLanding = true
                newEvent.isSimulator = false

        return EventRow(event: newEvent).environment(\.managedObjectContext, context)
        .previewLayout(.fixed(width: 300, height: 60))

    

【问题讨论】:

按照假设回答后更改问题是不好的做法。一问一答。错误不会改变行为,它是另一个错误 - 另一个故事。 对那个 Asperi 感到抱歉,但这是我发现发布更多代码的唯一方法。评论部分似乎不适合这样做。由于这个问题与我之前的问题密切相关,我认为跟进比提出新问题要好。 好的,在 ForEach 循环填充我的列表之后,通过应用 .listRowBackround 修饰符 ContentView 使其工作。似乎当列表由循环填充时,将修饰符应用于 EventRow 视图本身不起作用。感谢指向该修饰符@Asari 的指针,我需要几天才能找到它! 【参考方案1】:

这是一个使渐变行宽的解决方案

struct EventRow: View 

    var body: some View 
        VStack
            HStack 
                Text("Text one")
                Spacer()
                Text("Text two")
            
            HStack 
                Spacer()
                Image(systemName: "flame")
                    .font(.body)
                Spacer()
             // END of second HStack
                .padding(.top, -14)
         //END of Vstack
        .listRowBackground(LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom)
        )
    

【讨论】:

Asperi 再次来救援!谢谢,就像一个魅力。有趣的是,contentView 预览仍然显示我的旧布局,但在 sim 或设备上,结果是完美的。 尝试将此应用到我的实际项目中,但它似乎不起作用。我的实际 EventRow 文件从核心数据实体中提取其信息,但我怀疑这是问题所在。当我接近 10 项限制时尝试对元素进行分组,但没有帮助。将相应地编辑我的问题...

以上是关于SwiftUI 列表行布局的主要内容,如果未能解决你的问题,请参考以下文章

Swiftui - 列表第一项的不同视图(布局)

如何在 SwiftUI 列表行中具有相同的比例?

SwiftUI - 致命错误:每个布局项只能出现一次:文件 SwiftUI,第 0 行

带有部分的 SwiftUI 动态列表无法正确布局

SwiftUI 列表中基于约束的图像布局

更改内容顺序时,SwiftUI MacOS 列表布局出现故障