Home > Blockchain >  SwiftUI: Call a function of a programmatically created view
SwiftUI: Call a function of a programmatically created view

Time:07-25

I am trying to make a SwiftUI ScrollView scroll to a certain point in an abstracted view when a button is pressed in a view which is calling the abstracted view programmatically. Here is my code:

struct AbstractedView: View {
    @Namespace var view2ID

    var body: some View {
        ScrollView {
            VStack {
                View1()
                View2()
                .id(view2ID)
                View3()
            }
        }
    }
    func scrollToView2(_ proxy: ScrollViewProxy) {
        proxy.scrollTo(view2ID, anchor: .topTrailing)
    }
}

As you can see, when scrollToView2() is called (in a ScrollViewReader), the AbstractedView scrolls to view2ID. I am creating a number of AbstractedView's programmatically in a different View:

struct HigherView: View {
    var numAbstractedViewsToMake: Int

    var body: some View {
        VStack {
            HStack {
                ForEach (0..<numAbstractedViewsToMake, id: \.self) { _ in
                    AbstractedView()
                }
            }
            Text("button")
            .onTapGesture {
                /* call each AbstractedView.scrollToView2()
            }
        }
    }
}

If I stored these views in an array in a struct inside my HigherView with a ScrollViewReader for each AbstractedView would that work? I feel as though there has to be a nicer way to achieve this, I just have no clue how to do it. I am new to Swift so thank you for any help.

P.S. I have heard about UIKit but I don't know anything about it, is this the right time to be using that?

CodePudding user response:

Using the comments from @Asperi and @jnpdx, I was able to come up with a more powerful solution than I needed:

class ScrollToModel: ObservableObject {
    enum Action {
        case end
        case top
    }
    @Published var direction: Action? = nil
}

struct HigherView: View {
    @StateObject var vm = ScrollToModel()
    var numAbstractedViewsToMake: Int

    var body: some View {
        VStack {
            HStack {
                Button(action: { vm.direction = .top }) { // < here
                    Image(systemName: "arrow.up.to.line")
                      .padding(.horizontal)
                }
                Button(action: { vm.direction = .end }) { // << here
                    Image(systemName: "arrow.down.to.line")
                      .padding(.horizontal)
                }
            }
            Divider()
            HStack {
                ForEach(0..<numAbstractedViewsToMake, id: \.self) { _ in
                    ScrollToModelView(vm: vm)
                }
            }
        }
    }
}

struct AbstractedView: View {
    @ObservedObject var vm: ScrollToModel

    let items = (0..<200).map { $0 } // this is his demo
    var body: some View {
        VStack {
            
            ScrollViewReader { sp in
                ScrollView {
               
                    LazyVStack { // this bit can be changed accordingly
                        ForEach(items, id: \.self) { item in
                            VStack(alignment: .leading) {
                                Text("Item \(item)").id(item)
                                Divider()
                            }.frame(maxWidth: .infinity).padding(.horizontal)
                        }
                    }.onReceive(vm.$direction) { action in
                        guard !items.isEmpty else { return }
                        withAnimation {
                            switch action {
                                case .top:
                                    sp.scrollTo(items.first!, anchor: .top)
                                case .end:
                                    sp.scrollTo(items.last!, anchor: .bottom)
                                default:
                                    return
                            }
                        }
                    }
                }
            }
        }
    }
}

Thank you both!

  • Related