Я пытался понять, как работают preference и onPreferenceChange, поэтому я экспериментировал с несколькими иерархиями, к сожалению, сейчас я застрял в одной ситуации, когда onPreferenceChange больше не вызывается. Что странно для меня, так это факт, когда я (в нижней части структуры TestView) удаляю строки
.modifier (Border (.column)) ИЛИ Spacer (minLength: 0)
onPreferenceChange начинает работать нормально / вызывается так, как я ожидаю
Я пытался найти объяснение, но безуспешно. Может кто-нибудь объяснить мне, что я делаю неправильно?
Вот код моего root представления
public struct MyRootView: View {
public var body: some View {
TestView()
.onPreferenceChange(ChangeInfoKey.self) { changeInfo in
print("preference changed: \(changeInfo)")
}
}
}
TestView:
struct TestView: View {
@State private var changeInfo: ChangeInfo?
var body: some View {
VStack {
Group {
Button(action: {
self.changeInfo = ChangeInfo(title: "Some Title \(Int.random(in: 0...10))")
print("Change initiated: \(self.changeInfo!.title) - \(self.changeInfo!.id)")
}) {
Text("My Button")
}
.preference(key: ChangeInfoKey.self, value: changeInfo)
}
.modifier(Border(.column))
Spacer(minLength: 0)
}
}
}
Создает модификатор границы Я не уверен, что это только визуальная граница вокруг представления, если она имеет отношение к этой проблеме, но для тех, кто хочет полностью просмотреть все части моего кода или попробовать его:
struct Border: ViewModifier {
enum BorderType: RawRepresentable {
case section
case emptyColumn
case column
case widget
case debug
var rawValue: (CGFloat, CGFloat, Color) {
switch self {
case .section: return (2, 0, Color.blue)
case .emptyColumn: return (0.5, 4, Color(0xa7afb5))
case .column: return (0.5, 4, Color(0xa7afb5))
case .widget: return (0.5, 2, Color(0xa7afb5))
case .debug: return (4, 0, Color.red)
}
}
init?(rawValue: (CGFloat, CGFloat, Color)) {
fatalError("ElementBorder.init(rawValue) - not implemented")
}
}
let lineWidth: CGFloat
let color: Color
let dashLength: CGFloat
init(_ borderType: BorderType) {
self.lineWidth = borderType.rawValue.0
self.dashLength = borderType.rawValue.1
self.color = borderType.rawValue.2
}
func body(content: Content) -> some View {
if dashLength > 0 {
return AnyView(content
.overlay(
Rectangle()
.strokeBorder(style: StrokeStyle(lineWidth: self.lineWidth, dash: [self.dashLength]))
.foregroundColor(self.color)
))
} else {
return AnyView(content
.border(self.color, width: self.lineWidth)
)
}
}
}