Swiftui listRowInsets 在添加到空数组时会发生意外更改

Posted

技术标签:

【中文标题】Swiftui listRowInsets 在添加到空数组时会发生意外更改【英文标题】:Swiftui listRowInsets makes unexpected changes when adding to an empty array 【发布时间】:2021-09-20 20:23:49 【问题描述】:

我在这里重新创建了一个最小的可重现示例。我正在使用 Xcode 13 beta 5。

在我的项目中,我使用 List 和 ForEach 循环呈现记分卡列表。我正在使用滑动操作来删除记分卡。在我删除记分卡,然后添加记分卡后,列表会在前缘使用额外的填充或 listRowInset 呈现。

此外,在 ContentView 中,我使用 if/else 语句在记分卡数组为空时呈现消息。我认为这是错误发生的地方,但我真的不知道如何解决它。

列表应该是这样的......

Proper rendering of list

下面是出乎意料的错误渲染...

Improper rendering after deleting the scorecard and adding a new one

要重新创建错误,首先通过从后缘滑动删除记分卡,然后单击顶部的添加记分卡,您将在记分卡的前缘看到额外的空白。我将附上下面的代码...提前感谢您的帮助!

import SwiftUI

struct ContentView: View 

@State var scorecards = [
    Scorecard(date: Date()),
    
]

var sortedScorecards: [Scorecard] 
    get 
        scorecards.sorted 
            $0.date > $1.date
        
    
    set 
        scorecards = newValue
    

var body: some View 
    VStack 
        
        Button 
            scorecards = [
                Scorecard(date: Date()),
                
            ]
            
         label: 
            Text("Add Scorecard")
        
        
        
        if scorecards.count < 1 
            
            Spacer()
            
            HStack
                Spacer()
                Text("No previous scorecards. Start a scorecard!")
                    .font(.headline)
                    .padding(20)
                    .multilineTextAlignment(.center)
                Spacer()
            
            Spacer()
         else 
            List 
                ForEach(sortedScorecards, id:\.self)  scorecard in
                    if #available(ios 15.0, *) 
                        
                        Button 
                            
                         label: 
                            Card(scorecard: scorecard)
                            
                        .buttonStyle(.plain)
                            .listRowInsets(.init(top:7.5,
                                                 leading:0,
                                                 bottom:7.5,
                                                 trailing:0))
                            .swipeActions(edge: .trailing, allowsFullSwipe: false) 
                                Button("Delete Scorecard", role: .destructive) 
                                    deleteScorecard(scorecard: scorecard)
                                
                            
                        
                        
                     else 
                        // Fallback on earlier versions
                    
                
            
            .onAppear 
                UITableView.appearance().backgroundColor = .black
            
        
    
    


    func deleteScorecard(scorecard:Scorecard) 
        scorecards = scorecards.filter$0.id != scorecard.id
    




struct Card: View 
    
    var scorecard:Scorecard
    
    func scorecardDate(date:Date) -> String 
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .short
        return formatter.string(from: date)
    
    
    var body:some View 
        
        ZStack 
            Rectangle()
                .foregroundColor(Color.blue)
                .frame(height: 25)
            
            Text(scorecardDate(date:scorecard.date))
            
        
    

    
    
struct Scorecard:Hashable 
    func hash(into hasher: inout Hasher) 
        hasher.combine(id)
    
    
    var id = UUID().uuidString
    var date:Date

【问题讨论】:

你能创建一个minimal reproducible example吗?没有其他人可以编译您包含的代码,因为它依赖于您未包含的类型。 好主意@jnpdx,让我试试!谢谢 @jnpdx 我已经编辑了问题并添加了一个最小可重现示例的代码。感谢您的建议! 【参考方案1】:

确实似乎与if/else 语句有关。当 List 从视图层次结构中删除然后重新添加时,插图似乎变得一团糟。

插入的数量对我来说看起来很熟悉——就像在前导侧有一个删除按钮时应该插入的数量一样。所以,凭直觉,我添加了一个显式调用来将编辑模式设置为.inactive。这似乎行得通。

在您的视图顶部,添加以下内容:

@Environment(\.editMode) private var editMode

那么,在你的deleteScorecard(scorecard:Scorecard)

func deleteScorecard(scorecard:Scorecard) 
    scorecards = scorecards.filter$0.id != scorecard.id
    editMode?.wrappedValue = .inactive //<-- here

这似乎明确地关闭了编辑模式,然后避免了将List 添加回视图层次结构时的错误。


更新——次要解决方案。

这是我想出的另一个解决方案,因为我的代码适用于您的示例代码,但不适用于您的应用。在此版本中,List 始终包含在视图层次结构中,但如果没有任何项目,则框架的高度设置为 0。由于您设置的背景颜色,可能会产生副作用,这是我最初没有包含此内容的原因之一,但由于最初的解决方案并不理想,现在值得包括:

var body: some View 
    VStack 
        
        Button 
            scorecards = [
                Scorecard(date: Date()),
                
            ]
            
         label: 
            Text("Add Scorecard")
        
        
        
        if scorecards.count < 1 
            
            VStack 
                Spacer()
                
                HStack
                    Spacer()
                    Text("No previous scorecards. Start a scorecard!")
                        .font(.headline)
                        .padding(20)
                        .multilineTextAlignment(.center)
                    Spacer()
                
                Spacer()
            
            
        
        
        List 
            ForEach(sortedScorecards, id:\.self)  scorecard in
                if #available(iOS 15.0, *) 
                    
                    Button 
                        
                     label: 
                        Card(scorecard: scorecard)
                        
                    .buttonStyle(.plain)
                        .listRowInsets(.init(top:7.5,
                                             leading:0,
                                             bottom:7.5,
                                             trailing:0))
                        .swipeActions(edge: .trailing, allowsFullSwipe: false) 
                            Button("Delete Scorecard", role: .destructive) 
                                deleteScorecard(scorecard: scorecard)
                            
                        
                    
                    
                 else 
                    // Fallback on earlier versions
                
            
        
        .frame(maxHeight: scorecards.count == 0 ? 0 : .infinity)
        .onAppear 
            UITableView.appearance().backgroundColor = .black
        
    
    

【讨论】:

您的解决方案确实适用于我的示例代码,但不适用于我的项目。我想可能是我的项目中的 bc,我使用了 ViewModel 中的已发布属性数组,而不是状态属性数组。我重构了我的示例代码以使用与我的项目相同的项目结构,并且您的解决方案仍然有效,但由于某种原因它不适用于我的项目。我得继续试验 查看我的更新以获得另一个解决方案。如果这些都不起作用,我想最好尝试包含一个更准确地反映我的原始解决方案似乎不适合您的实际项目环境的示例。 第二个解决方案做到了!太感谢了!非常感谢您花时间提供两个解决方案并解释您所做的事情。非常聪明和有创意的解决方案

以上是关于Swiftui listRowInsets 在添加到空数组时会发生意外更改的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:listRowInsets 未按预期工作

SwiftUI:当“navigationBarItems”修改列表时,“listRowInsets”无法按预期工作[重复]

如何在 SwiftUI 中删除列表的左右填充?

带有 .listRowInsets(EdgeInsets()) 的披露指标

如何在 UIkit 中添加 SwiftUI 对象

在 SwiftUI 中向 TextField/SecureField 添加图像,向占位符文本添加填充