1

In iOS 14 you can use ScrollViewReader to automatically scroll your view up or down as the content in the scrollview changes.

I'm in a situation where I have to support iOS 13. Is there a way, even a hacky way, to programmatically scroll the scrollview in iOS 13?

For that, I write the following code it works with vertical scrolling but I need horizontal scroll and it needs to move the selected Index.

    struct ListScrollingHelper: UIViewRepresentable {
        let proxy: ListScrollingProxy // reference type
    
        func makeUIView(context: Context) -> UIView {
            return UIView() // managed by SwiftUI, no overloads
        }
    
        func updateUIView(_ uiView: UIView, context: Context) {
            proxy.catchScrollView(for: uiView) // here UIView is in view hierarchy
        }
    }

class ListScrollingProxy {
    enum Action {
        case end
        case top
        case point(point: CGPoint)     // << bonus !!
    }

    private var scrollView: UIScrollView?

    func catchScrollView(for view: UIView) {
        if nil == scrollView {
            scrollView = view.enclosingScrollView()
        }
    }

    func scrollTo(_ action: Action) {
        if let scroller = scrollView {
            var rect = CGRect(origin: .zero, size: CGSize(width: 1, height: 1))
            switch action {
                case .end:
                    rect.origin.y = scroller.contentSize.height +
                        scroller.contentInset.bottom + scroller.contentInset.top - 1
                case .point(let point):
                    rect.origin.y = point.y
                default: {
                    // default goes to top
                }()
            }
            scroller.scrollRectToVisible(rect, animated: true)
        }
    }
}

extension UIView {
    func enclosingScrollView() -> UIScrollView? {
        var next: UIView? = self
        repeat {
            next = next?.superview
            if let scrollview = next as? UIScrollView {
                return scrollview
            }
        } while next != nil
        return nil
    }
}

i use my code as follows:

struct ContentView: View {
    private let scrollingProxy = ListScrollingProxy() // proxy helper

    var body: some View {
        VStack {
            HStack {
                Button(action: { self.scrollingProxy.scrollTo(.top) }) { // < here
                    Image(systemName: "arrow.up.to.line")
                      .padding(.horizontal)
                }
                Button(action: { self.scrollingProxy.scrollTo(.end) }) { // << here
                    Image(systemName: "arrow.down.to.line")
                      .padding(.horizontal)
                }
            }
            Divider()
            List {
                ForEach(0 ..< 200) { i in
                    Text("Item \(i)")
                        .background(
                           ListScrollingHelper(proxy: self.scrollingProxy) // injection
                        )
                }
            }
        }
    }
}
0

1 Answer 1

1

Use the following approach:

import SwiftUI

struct ContentView: View {    
    
    var body: some View {            
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 10) {
                ForEach(1..<11) {
                    Text("ITEM \($0)")
                        .frame(width: 70, height: 70)
                }
            }
        }
    }
}

Scrolling a whole table looks like this:

struct ContentView: View {
        
    var body: some View {
        List {
            ScrollView(.horizontal, showsIndicators: false) {       
                Text("First List Item in a first cell")
                Text("Second List Item in a second cell")
                Text("Third List Item in a third cell")
            }
        }
    }
}

You can combine both methodologies.

Sign up to request clarification or add additional context in comments.

1 Comment

Here where we can use the scroll view scroll property

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.