How to prevent automatic scrolling of UIScrollView during drag & drop?

Hi,


When dragging a view inside UIScrollView using UIDragInteraction/UIDropInteraction, the scroll view *automatically* scrolls as you drag your view near the edge of the screen. How can you prevent this behavior? I want to disable *only* the automatic scrolling, not the scrolling itself, so that the user can scroll with the second finger if he so chooses. I know I can disable scrolling using isScrollEnabled, but this will also disable the user-initiated scrolling.


Thanks.

Post not yet marked as solved Up vote post of tamadeveloper Down vote post of tamadeveloper
6.3k views

Replies

I think I see what you want, but I'd be worried about modifying a UI action that is otherwise mandated by the system. Point is that Apple has already trained users to expect the UI to perform in a prescribed manner (see 'feels natural' below). Changing it might violate that flow. Not being able to casually disable just auto could be that mandate in action.


In practice, w/that example, as you point out, the user can already control scrolling. That said, and without testing, I can imagine an example where you fully DIY an additional layer above the system UI that captures the user's touches and moves a child view's inbounds contents at will, under your full control. But whether or not app review would complain is unknown.


Quoting the HIGs:


"Scroll Views

A scroll view allows users to browse content, such as text in a document or a collection of images, that’s larger than the visible area. As people swipe, flick, drag, tap, and pinch, a scroll view follows the gesture, revealing or zooming content in a way that feels natural. A scroll view itself has no appearance, but does display transient scrolling indicators as people interact with it. A scroll view can also be configured to operate in paging mode, where scrolling reveals an entirely new page of content rather than moving around the current page."


Perhaps if you can provide better context to your specific goal (map app, game, product catalog, reader, etc.), someone can offer a suggestion that satisfies you and Apple.

That is not exactly what you are looking for, but you could slow down scrolling:

scrollView.decelerationRate = UIScrollView.DecelerationRate.fast


See

https://stackoverflow.com/questions/11561992/sensitivity-scroll-speed-of-uiscrollview-with-paging


for more sophisticated behavior.

I had a similar problem when I was using a UIScrollView within my collection view cells and performing a drag and drop operation. I was able to solve this by using a custom subclass for UIScrollView and overriding the following method:

    override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
        // NOTE: this fixes an issue where dragging within the collection view during a drag and drop
        // action would automatically scroll the view to try and "make room" for the dragged item.
        if let collectionView: UICollectionView = self.superviewOfType(), collectionView.hasActiveDrag {
            return
        }
        super.setContentOffset(contentOffset, animated: animated)
    }

Which makes use of a helper method to find a superview of a given type:

extension UIView {
    func superviewOfType<T: UIView>() -> T? {
        var currentView: UIView? = self
        while currentView?.superview != nil {
            if let typedView = currentView as? T {
                return typedView
            }
            currentView = currentView?.superview
        }
        return nil
    }
}

This essentially will prevent any automatic scrolling from happening any time a parent collection view is performing a drag. Hope this helps!