jwarris91
jwarris91

Reputation: 952

Detecting ScrollOffset in ScrollView inside ViewController held within UIPageViewController?

I hava a UIPageViewController that holds an array of ContentUIViewController, these have scrollviews in them.

When the scrollview scrolls I want to recognise this in the view controller that is the parent of the UIPageViewController (added as child)

What would be the best route to achieve this? as currently I tried delegating the didScroll back to the viewmodel for the ContentUIViewController then feeding that into the parent of the UIPageViewController to adjust header height that I want to collapse, but it doesn't work well / is very hacky

Is there a way to read delegate output in the a child vc to the parent vc without feeding it back through viewmodels? This is proving tricky due to the array nature of the UIPageViewController rather than a single child VC.

Updated:

private func generateContentControllers() -> [UIViewController] {
    var viewControllers: [UIViewController] = []
        viewControllers.append(ScrollableContentViewController(contentViews: infoViews))
        viewControllers.append(reviewsVC)
        viewControllers.append(ScrollableContentViewController(contentViews: helpViews))
    }
    return viewControllers
}

Provided via

var scrollingViewControllers: [UIViewController] { get }

Added with

    if let firstViewController = self.viewModel.scrollingViewControllers.first {
        pagingController.setViewControllers([firstViewController], direction: .forward, animated: false)
    }

Upvotes: 0

Views: 273

Answers (1)

PGDev
PGDev

Reputation: 24341

Here is how you can get that working.

1. Create a handler in ContentUIViewController that will be called in scrollViewDidScroll(_:) method for each contentOffset change.

class ContentUIViewController: UIViewController, UIScrollViewDelegate {
    var handler: ((CGPoint)->())?

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        handler?(scrollView.contentOffset)
    }
}

2. In ParentVC, create an instance of UIPageViewController and add it as a child to it. I think you did that already.

What you need to do next is create an array of ContentUIViewController and for each instance set the handler that we created earlier.

This handler will be called every time the scrollView is scrolled in that particular ContentUIViewController. We'll get the contentOffset of the scrollView here. Call updateHeaderHeight(for:) with the obtained contentOffset to adjust the header height.

class ViewModel {
    private func generateContentControllers() -> [ContentUIViewController] {
        var viewControllers: [ContentUIViewController] = []
        //add your code here....
        return viewControllers
    }

    lazy var scrollingViewControllers: [ContentUIViewController] = {
        return self.generateContentControllers()
    }()
}

class ParentVC: UIViewController {
    let viewModel = ViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.viewModel.scrollingViewControllers.forEach {
            $0.handler = {(offset) in
                self.updateHeaderHeight(for: offset)
            }
        }
    }

    func updateHeaderHeight(for offset: CGPoint) {
        //add the code to adjust header height here...
    }

    //add rest of the code for pageViewController here....
}

Upvotes: 1

Related Questions