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:当“navigationBarItems”修改列表时,“listRowInsets”无法按预期工作[重复]