Swiftui listRowInsets 在添加到空数组时进行意外更改
Swiftui listRowInsets makes unexpected changes when adding to an empty array
我在这里重新创建了一个最小的可重现示例。我正在使用 Xcode 13 beta 5.
在我的项目中,我使用 List 和 ForEach 循环渲染记分卡列表。我正在使用 swipeactions 来删除记分卡。在我删除记分卡并添加记分卡后,列表会在前缘呈现额外的填充或 listRowInset。
此外,在 ContentView 中,我使用 if/else 语句在记分卡数组为空时呈现消息。我认为这是错误发生的地方,但真的不知道如何解决它。
列表应该是这样的...
Proper rendering of list
下面是意想不到的错误渲染...
Improper rendering after deleting the scorecard and adding a new one
要重现错误,首先从后缘滑动删除记分卡,然后单击顶部的添加记分卡,您将在记分卡的前缘看到额外的白色 space。我将在下面附上代码...在此先感谢您的帮助!
import SwiftUI
struct ContentView: View {
@State var scorecards = [
Scorecard(date: Date()),
]
var sortedScorecards: [Scorecard] {
get {
scorecards.sorted {
[=10=].date > .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{[=10=].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
}
它确实似乎与if/else
声明有关。当 List
从视图层次结构中删除然后重新添加时,插图似乎被弄乱了。
插入的数量对我来说看起来很熟悉 -- 就像如果前面有一个删除按钮时应该插入的数量一样。因此,凭直觉我添加了一个显式调用以将编辑模式设置为 .inactive
。这似乎有效。
在您的视图顶部,添加以下内容:
@Environment(\.editMode) private var editMode
然后,在您的 deleteScorecard(scorecard:Scorecard)
:
func deleteScorecard(scorecard:Scorecard) {
scorecards = scorecards.filter{[=11=].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
}
}
}
我在这里重新创建了一个最小的可重现示例。我正在使用 Xcode 13 beta 5.
在我的项目中,我使用 List 和 ForEach 循环渲染记分卡列表。我正在使用 swipeactions 来删除记分卡。在我删除记分卡并添加记分卡后,列表会在前缘呈现额外的填充或 listRowInset。
此外,在 ContentView 中,我使用 if/else 语句在记分卡数组为空时呈现消息。我认为这是错误发生的地方,但真的不知道如何解决它。
列表应该是这样的...
Proper rendering of list
下面是意想不到的错误渲染...
Improper rendering after deleting the scorecard and adding a new one
要重现错误,首先从后缘滑动删除记分卡,然后单击顶部的添加记分卡,您将在记分卡的前缘看到额外的白色 space。我将在下面附上代码...在此先感谢您的帮助!
import SwiftUI
struct ContentView: View {
@State var scorecards = [
Scorecard(date: Date()),
]
var sortedScorecards: [Scorecard] {
get {
scorecards.sorted {
[=10=].date > .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{[=10=].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
}
它确实似乎与if/else
声明有关。当 List
从视图层次结构中删除然后重新添加时,插图似乎被弄乱了。
插入的数量对我来说看起来很熟悉 -- 就像如果前面有一个删除按钮时应该插入的数量一样。因此,凭直觉我添加了一个显式调用以将编辑模式设置为 .inactive
。这似乎有效。
在您的视图顶部,添加以下内容:
@Environment(\.editMode) private var editMode
然后,在您的 deleteScorecard(scorecard:Scorecard)
:
func deleteScorecard(scorecard:Scorecard) {
scorecards = scorecards.filter{[=11=].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
}
}
}