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

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
}
}


Hey there, future programmers!

After playing with disassembler for a while trying to find the root cause of this old bug I have found that it is probably "autoscroll" logic, clashing with UIPageViewController paging logic.

In my case, disabling the autoscroll using aforementioned hack with dataSource = nil is not plausible, since I want exactly what autoscroll offers in drag session.

The only solution that I have found is to opt out of UIPageViewController completely and to implement my paging view controller using plain old UIScrollView with isPagingEnabled = true.

It is a bit of a complex task to implement dynamic page loading this way, but should not be a roadblock for the experienced developers.

Weird UIPageViewController + drag bug
 
 
Q