Weird UIPageViewController + drag bug

I'm seeing a weird interaction between UIPageViewController and dragging. When a drag hovers over a UIPageViewController set up to scroll horizontally, it'll randomly scroll a full page's worth leftwards, into blank space. Dragging the page-controller view slightly restores it to where it should be.


I can replicate this in a trivially simple project, but I can't find a good workaround. It feels like something in the internals is spring-loaded that shouldn't be, but I'm not sure how to squish this behaviour.


My app is build around a UIPageController as the main container vc and makes heavy use of drag and drop, and this behaviour is not just an occasionaly glitch, but an absolute killer.


Anyone got any ideas what I can poke at?


Edit: rdar://34926095

Replies

Did you find any solution yet? I'm having the same issue (with vertical PageViewController scrolling). Really want to implement Drag & Drop, but it always glitches to a blank screen ...

I have this bug yet (iOS 12), did you find a solution?

I found workaround for this, you need to set pageviewcontroller datasource delegate to nil during drag, and then set it again at end dragging.

    // WORKAROUND
    // When Dragging to edge of the screen in UIPageViewController, page controller switch page to a blank page

    func collectionView(_ collectionView: UICollectionView, dragSessionWillBegin session: UIDragSession) {
        if let pageController = self.parent as? UIPageViewController {
            self.tmpPageViewControllerDataSource = pageController.dataSource
            pageController.dataSource = nil
        }
    }

    func collectionView(_ collectionView: UICollectionView, dragSessionDidEnd session: UIDragSession) {
        if let pageController = self.parent as? UIPageViewController {
            pageController.dataSource = self.tmpPageViewControllerDataSource
            self.tmpPageViewControllerDataSource = nil
        }
    }
This might work.

Code Block
class BuglessPageViewController: UIPageViewController {
private var preventScrollBug = true
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
override func setViewControllers(_ viewControllers: [UIViewController]?, direction: UIPageViewController.NavigationDirection, animated: Bool, completion: ((Bool) -> Void)? = nil) {
preventScrollBug = false
super.setViewControllers(viewControllers, direction: direction, animated: animated) { completed in
self.preventScrollBug = true
if completion != nil {
completion!(completed)
}
}
}
}
extension BuglessPageViewController: UIScrollViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
preventScrollBug = false
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if preventScrollBug {
scrollView.setContentOffset(CGPoint(x: view.frame.width, y: 0), animated: false)
}
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
preventScrollBug = true
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
preventScrollBug = true
}
}
extension UIPageViewController {
var scrollView: UIScrollView! {
for view in view.subviews {
if let scrollView = view as? UIScrollView {
return scrollView
}
}
return nil
}
}