Actualizado para proporcionar un ejemplo reproducible completo.
Tengo una vista MainView con dos subvistas, MainTextView y TableOfContentsView . Quiero seleccionar un elemento en TableOfContentsView que desencadena un cambio de posición de desplazamiento en MainTextView .
Tengo un @State var scrollPosition: Int en MainView que se pasa a un @Binding var scrollPosition: Int en MainTextView . Aquí está el código para mis 3 vistas.
struct MainView: View { @State private var showingToc = false @State private var scrollPosition = 0 var body: some View { VStack(alignment: .leading) { Text("Table of Contents (chapter \(scrollPosition + 1))") .onTapGesture { showingToc = !showingToc } Divider() if showingToc { TableOfContentsView( onChapterSelected: { chapter in scrollPosition = chapter showingToc = false } ) } else { MainTextView(scrollPosition: $scrollPosition) } } } } struct TableOfContentsView: View { var onChapterSelected: (Int) -> Void var body: some View { ScrollView { VStack { ForEach(0 ..< 20) { i in Text("Chapter \(i + 1)") .onTapGesture { onChapterSelected(i) } } } } } } struct MainTextView: View { let lorumIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." @Binding var scrollPosition: Int @State private var scrollProxy: ScrollViewProxy? = nil var body: some View { ScrollView { ScrollViewReader { proxy in VStack(alignment: .leading) { ForEach(0 ..< 20) { i in VStack(alignment: .leading) { Text("Chapter \(i + 1)") .frame(maxWidth: .infinity, alignment: .center) .padding(.top) Text(lorumIpsum) .font(.system(size: 18, design: .serif)) .padding(.top) } .padding(.bottom, 20) .id(i) } } .padding(.leading) .padding(.trailing) .onAppear { scrollProxy = proxy } } } .onChange(of: scrollPosition) { target in scrollProxy?.scrollTo(target, anchor: .top) } } } Mi función .onChange nunca se llama: si coloco un punto de interrupción dentro, nunca llega al punto de interrupción. ¿Que me estoy perdiendo aqui? ¿Cómo observo un @Binding que se cambia desde fuera de la vista?
No se llamará a .onChange porque MainTextView no existe cuando showingToc = true debido al bloque condicional:
if showingToc { TableOfContentsView(onChapterSelected: { chapter in scrollPosition = chapter showingToc = false } ) } else { MainTextView(scrollPosition: $scrollPosition) } Es posible que desee considerar mostrar TOC como una superposición. Pero para que su código actual funcione, debe llamar a proxy.scrollTo en su .onAppear de MainTextView :
.onAppear { scrollProxy = proxy scrollProxy?.scrollTo(scrollPosition, anchor: .top) }