My scenario is simple, I have a parent view that has a button and a child view that has a timeline. What I would like to do is when I click my parent view button to move my child view timeline view to the top. I have been able to do that but only if the button is already in that same child view as the timeline view, I can not seem to get it to work when clicking the parent view button. If you look at my code below Button B works because it is in the same view as the TimeLine, however how can I make it so that when I click Button A in the parent view I can get my timeline to go to the top like in Button B ? Any suggestions would be great. My code below will also work in Xcode.
struct ExampleUpdateListBind: View {
var body: some View {
VStack {
Text("Button A")
.onTapGesture {
print("By Clicking this one my timeline child view should scroll to the top")
}
.padding(.leading, 10)
MYListExamples()
}
}
}
struct MYListExamples: View {
var myList = ["X First Row","John","Abe","Joseph","Adam","John","Abe","Joseph","Adam",
"Joseph","Adam","John","Abe","Joseph","Adam","Joseph","Adam","John","Abe","Joseph","Adam"
,"Joseph","Adam","John","Abe","Joseph","Adam","Joseph","Adam","John","Abe","Joseph","Adam"
,"Joseph","Adam","John","Abe","Joseph","Adam","Joseph","Adam","John","Abe","Joseph","Adam"]
var body: some View {
let result = myList.sorted {
$0 > $1
}
ScrollViewReader { (proxy: ScrollViewProxy) in
Button("Button B") {
proxy.scrollTo(result[0], anchor: .top)
}
List {
ForEach(result) { i in
Text(i)
}
}
}
}
}
CodePudding user response:
You'll need to keep some sort of state or publisher in the parent view that is passed down to the child view, which will most likely observe it via onChange or onReceive.
Here's a very simple version:
import SwiftUI
import Combine //possibly necessary if using a Publisher-based solution
struct ExampleUpdateListBind: View {
@State private var send = Date()
var body: some View {
VStack {
Text("Button A")
.onTapGesture {
send = Date()
}
.padding(.leading, 10)
MYListExamples(receive: send)
}
}
}
struct MYListExamples: View {
var receive : Date
var myList = ["X First Row","John","Abe","Joseph","Adam","John","Abe","Joseph","Adam",
"Joseph","Adam","John","Abe","Joseph","Adam","Joseph","Adam","John","Abe","Joseph","Adam"
,"Joseph","Adam","John","Abe","Joseph","Adam","Joseph","Adam","John","Abe","Joseph","Adam"
,"Joseph","Adam","John","Abe","Joseph","Adam","Joseph","Adam","John","Abe","Joseph","Adam"]
var body: some View {
let result = myList.sorted {
$0 > $1
}
ScrollViewReader { (proxy: ScrollViewProxy) in
Button("Button B") {
proxy.scrollTo(result[0], anchor: .top)
}
.onChange(of: receive) { _ in
proxy.scrollTo(result[0], anchor: .top)
}
List {
ForEach(result, id: \.self) { I in //note that in a real-world case, we wouldn't want to use \.self with strings that have duplicate values like the data provided in the original question above
Text(i)
}
}
}
}
}
Other solutions could include passing a reference to a Publisher and using onReceive or storing the state in an ObservableObject that gets passed to the child view -- the premise is the same no matter what the scenario.
