SwiftUI:List/ForEach 中的滑块行为异常
Posted
技术标签:
【中文标题】SwiftUI:List/ForEach 中的滑块行为异常【英文标题】:SwiftUI: Slider in List/ForEach behaves strangely 【发布时间】:2021-12-30 22:58:33 【问题描述】:如果没有来自我没有的第二台设备的录音很难解释,但是当我尝试滑动滑块时,当我的手指肯定还在移动时它会停止。
我在下面发布了我的代码。我很乐意回答任何问题并进行解释。我确信这是我应该知道的非常简单的事情。任何帮助将不胜感激,谢谢!
import SwiftUI
class SettingsViewModel: ObservableObject
@Published var selectedTips = [
10.0,
15.0,
18.0,
20.0,
25.0
]
func addTip()
selectedTips.append(0.0)
selectedTips.sort()
func removeTip(index: Int)
selectedTips.remove(at: index)
selectedTips = selectedTips.compactMap $0
struct SettingsTipsView: View
@StateObject var model = SettingsViewModel()
var body: some View
List
HStack
Text("Edit Suggested Tips")
.font(.title2)
.fontWeight(.semibold)
Spacer()
if(model.selectedTips.count < 5)
Button(action: model.addTip() , label:
Image(systemName: "plus.circle.fill")
.renderingMode(.original)
.font(.title3)
.padding(.horizontal, 10)
)
.buttonStyle(BorderlessButtonStyle())
ForEach(model.selectedTips, id: \.self) tip in
let i = model.selectedTips.firstIndex(of: tip)!
//If I don't have this debug line here then the LAST slider in the list tries to force the value to 1 constantly, even if I remove the last one, the new last slider does the same. It's from a separate file but it's pretty much the same as the array above. An explanation would be great.
Text("\(CalculatorViewModel.suggestedTips[i])")
HStack
Text("\(tip, specifier: "%.0f")%")
Slider(value: $model.selectedTips[i], in: 1...99, label: Text("Label") )
if(model.selectedTips.count > 1)
Button(action: model.removeTip(index: i) , label:
Image(systemName: "minus.circle.fill")
.renderingMode(.original)
.font(.title3)
.padding(.horizontal, 10)
)
.buttonStyle(BorderlessButtonStyle())
【问题讨论】:
看起来你可能需要在ForEach
中使用 ios15 的基于列表的绑定 - 在 hackingwithswift.com/quick-start/swiftui/… 使用 Swift 的技巧进行黑客攻击应该会给你一些线索吗?
我实际上也允许 iOS 14 上的设备使用该应用程序,您还有什么可以推荐的吗?
【参考方案1】:
在 List
或 ForEach
中使用 id: \.self
在 SwiftUI 中是一个危险的想法。系统使用它来识别它期望的独特元素。但是,只要您移动滑块,您就会改变最终的小费值等于列表中的另一个值。然后,SwiftUI 会混淆哪个元素是哪个。
要解决此问题,您可以使用具有真正唯一 ID 的项目。您还应该尽量避免使用索引来引用列表中的某些项目。我已经使用列表绑定来避免这个问题。
struct Tip : Identifiable
var id = UUID()
var tip : Double
class SettingsViewModel: ObservableObject
@Published var selectedTips : [Tip] = [
.init(tip:10.0),
.init(tip:15.0),
.init(tip:18.0),
.init(tip:20.0),
.init(tip:25.0)
]
func addTip()
selectedTips.append(.init(tip:0.0))
selectedTips = selectedTips.sorted(by: a, b in
a.tip < b.tip
)
func removeTip(id: UUID)
selectedTips = selectedTips.filter $0.id != id
struct SettingsTipsView: View
@StateObject var model = SettingsViewModel()
var body: some View
List
HStack
Text("Edit Suggested Tips")
.font(.title2)
.fontWeight(.semibold)
Spacer()
if(model.selectedTips.count < 5)
Button(action: model.addTip() , label:
Image(systemName: "plus.circle.fill")
.renderingMode(.original)
.font(.title3)
.padding(.horizontal, 10)
)
.buttonStyle(BorderlessButtonStyle())
ForEach($model.selectedTips, id: \.id) $tip in
HStack
Text("\(tip.tip, specifier: "%.0f")%")
.frame(width: 50) //Otherwise, the width changes while moving the slider. You could get fancier and try to use alignment guides for a more robust solution
Slider(value: $tip.tip, in: 1...99, label: Text("Label") )
if(model.selectedTips.count > 1)
Button(action: model.removeTip(id: tip.id) , label:
Image(systemName: "minus.circle.fill")
.renderingMode(.original)
.font(.title3)
.padding(.horizontal, 10)
)
.buttonStyle(BorderlessButtonStyle())
【讨论】:
感谢您的回复!当我有时间在我的笔记本电脑上试用它时,我会告诉你它是如何工作的。 工作就像一个魅力!谢谢!以上是关于SwiftUI:List/ForEach 中的滑块行为异常的主要内容,如果未能解决你的问题,请参考以下文章