это должно сработать
import SwiftUI
struct ContentView: View {
@State var showDetails = false
@State var firstToggle = false
@State var secondToggle = false
var body: some View {
NavigationView {
Form {
ToggleSubtitleRow(title: "Show Advanced",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, se",
isOn: $showDetails)
if showDetails {
ToggleSubtitleRow(title: "Lorem ipsum dolor sit amet",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam",
isOn: $firstToggle).id(UUID())
ToggleSubtitleRow(title: "Lorem ipsum dolor sit amet",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam",
isOn: $secondToggle)
}
}
.listStyle(GroupedListStyle())
.navigationBarTitle("Settings", displayMode: .inline)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
public struct ToggleSubtitleRow: View {
let title: String
let text: String
@Binding var isOn: Bool
public var body: some View {
VStack(alignment: .leading) {
Toggle(isOn: $isOn) {
Text(title)
}
Text(text)
.fixedSize(horizontal: false, vertical: true)
.foregroundColor(Color(.secondaryLabel))
.frame(alignment: .leading)
}
.foregroundColor(Color(.label))
}
}
Я положил это здесь, чтобы показать, что вся условная часть воссоздается, если хотя бы один из ее элементов должен быть воссоздан.
Для объяснения, немного изменить код (без какого-либо модификатора .id)
if showDetails {
Text("\(showDetails.description)")
ToggleSubtitleRow(title: "Lorem ipsum dolor sit amet",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam",
isOn: $firstToggle)
ToggleSubtitleRow(title: "Lorem ipsum dolor sit amet",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam",
isOn: $secondToggle)
}
Работает «как положено», потому что в условной части SwiftUI распознал «что-то», было изменено.
Text("\(showDetails.description)")
имеет тот же эффект.
А как насчет модификатора .id? Почему это работает?
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension View {
/// Returns a view whose identity is explicitly bound to the proxy
/// value `id`. When `id` changes the identity of the view (for
/// example, its state) is reset.
@inlinable public func id<ID>(_ id: ID) -> some View where ID : Hashable
}
На основании написанного
ToggleSubtitleRow(title: "Lorem ipsum dolor sit amet",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam",
isOn: $firstToggle).id(showDetails)
тоже работает!
Позволяет перестроить код таким образом
struct ContentView: View {
@State var showDetails = false
@State var firstToggle = false
@State var secondToggle = false
var body: some View {
let g = Group {
if showDetails {
ToggleSubtitleRow(title: "Lorem ipsum dolor sit amet",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam",
isOn: $firstToggle).id(UUID())
ToggleSubtitleRow(title: "Lorem ipsum dolor sit amet",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam",
isOn: $secondToggle)
}
}
let f = Form {
ToggleSubtitleRow(title: "Show Advanced",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, se",
isOn: $showDetails)
g
}
.listStyle(GroupedListStyle())
.navigationBarTitle("Settings", displayMode: .inline)
let v = NavigationView {
f
}
return v
}
}
и проверим тип g
let g: Group<TupleView<(some View, ToggleSubtitleRow)>?>
, мы увидим, как SwiftUI справляется с нашим «условным». Фактически это
TupleView<(some View, ToggleSubtitleRow)>?
ОБНОВЛЕНИЕ, основанное на обсуждении, применение модификатора .id к нескольким ToggleSubtitleRow просто не работает
Лучший вариант, как решить эту ошибку - переопределить
public struct ToggleSubtitleRow: View {
let title: String
let text: String
@Binding var isOn: Bool
public var body: some View {
VStack(alignment: .leading) {
Toggle(isOn: $isOn) {
Text(title)
}.id(UUID())
Text(text)
.fixedSize(horizontal: false, vertical: true)
.foregroundColor(Color(.secondaryLabel))
.frame(alignment: .leading)
}
.foregroundColor(Color(.label))
}
}
, не изменяя ничего в вашем ContentView, а непосредственно переключая себя в ToggleSubtitleRow