How can I programmatically force-stop scrolling in a UIScrollView?

IphoneUiscrollview

Iphone Problem Overview


Note: The answer given here doesn't work for me.

I have a UIScrollView (not a table view, just a custom thing), and when the user takes certain actions, I want to kill any scrolling (dragging or deceleration) inside the view. I've tried doing e.g. this:

[scrollView scrollRectToVisible:CGRectInset([scrollView bounds], 10, 10) animated:NO];

on the theory that, given a rect that's already known visible, the scrolling will just stop where it is, but it turns out that this doesn't have any effect-- apparently the scroll view sees that the given rect is in bounds and takes no action. I can get the scroll to stop, if I give a rect that is definitely outside the currently-visible bounds, but inside the contentSize of the view. This seems to halt the view as expected... but also causes it to jump to some other location. I could probably do a little playing around at the margins to get this to work reasonably OK, but does anyone know of a clean way to halt a scroll view that's doing its thing?

Thanks.

Iphone Solutions


Solution 1 - Iphone

I played with your original solution a bit, and this seems to work just fine. I think you almost had it, but you were just offsetting the rect that you used too much, and forgot that you could just scroll the rect straight back to the original rect.

The generalized solution for any scrolling action is this:

- (void)killScroll 
{
    CGPoint offset = scrollView.contentOffset;
    offset.x -= 1.0;
    offset.y -= 1.0;
    [scrollView setContentOffset:offset animated:NO];
    offset.x += 1.0;
    offset.y += 1.0;
    [scrollView setContentOffset:offset animated:NO];
}

[Edit] As of iOS 4.3 (and possibly earlier) this also appears to work

- (void)killScroll 
{
    CGPoint offset = scrollView.contentOffset;
    [scrollView setContentOffset:offset animated:NO];
}

Solution 2 - Iphone

The generic answer is, that [scrollView setContentOffset:offset animated:NO] is not the same as [scrollView setContentOffset:offset] !

  • [scrollView setContentOffset:offset animated:NO] actually stops any running animation.
  • [scrollView setContentOffset:offset] doesn't stop any running animation.
  • Same for scrollView.contentOffset = offset: doesn't stop any running animation.

That's not documented anywhere, but that's the behavior as tested on iOS 6.1 & iOS 7.1 - probably also before.

So the solution to stop a running animation / deceleration is simple as that:

[scrollView setContentOffset:scrollView.contentOffset animated:NO];

Basically what David Liu said in his edited answer. But I wanted to make clear, that these two APIs are NOT the same.

Swift 3:

scrollView.setContentOffset(scrollView.contentOffset, animated:false)

Solution 3 - Iphone

For me, David Lui's accepted answer above didn't work for me. This is what I ended up doing:

- (void)killScroll {
    self.scrollView.scrollEnabled = NO;
    self.scrollView.scrollEnabled = YES;
}

For what it is worth, I'm using the iOS 6.0 iPhone Simulator.

Solution 4 - Iphone

This is what I do for my scroll views and all other related subclasses:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
 {
    *targetContentOffset = scrollView.contentOffset;
 }

This sets the targetContentOffset to the scrollView's current offset, thus making the scrolling to stop because it has reached the target. It actually makes sense to use a method whose purpose is that users could set the targeted contentOffset.

Swift
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    targetContentOffset.pointee = scrollView.contentOffset
}

Solution 5 - Iphone

Stop the scroll in swift:

scrollView.setContentOffset(scrollView.contentOffset, animated: false)

Solution 6 - Iphone

Actually ... The most "modern" way would be -->

scrollview.panGestureRecognizer.enabled = false;
scrollview.panGestureRecognizer.enabled = true;

This deactivates the gesture-recognizer that is responsible for scrolling for just a moment which will kill the current touch. The user would need to lift the finger and put it back down to start scrolling again.

Edit: This actually just kills the current dragging of the user but does not immediately stop the deceleration if the scrollview is in this state currently. To do this the accepted answers edit is pretty much the best way xD

[scrollview setContentOffset: scrollview.contentOffset animated:false];

Solution 7 - Iphone

The cleanest way will be subclassing UIScrollView and providing your own setContentOffset method. This should pass the message on, only if you haven't switched on your freeze boolean property.

Like so:

BOOL freeze; // and the @property, @synthesize lines..

-(void)setContentOffset:(CGPoint)offset
{
	if ( !freeze ) [super setContentOffset:offset];
}

Then, to freeze:

scrollView.freeze = YES;

Solution 8 - Iphone

This answer worked for me: https://stackoverflow.com/questions/1105647/deactivate-uiscrollview-decelerating

-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{
    [scrollView setContentOffset:scrollView.contentOffset animated:YES];
}

Solution 9 - Iphone

Disable just scroll user interaction. (swift)
scrollView.isScrollEnabled = false
Disable in during scroll animation after dragging. (swift)
var scrollingByVelocity = false

func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
    if !scrollingByVelocity {
        scrollView.setContentOffset(scrollView.contentOffset, animated: false)
    }
}

Solution 10 - Iphone

This works for me in Swift 4.2:

   func killScroll() {
    self.scrollView.isScrollEnabled = false;
    self.scrollView.isScrollEnabled = true;
}

... as an extension:

extension UIScrollView {
    func killScroll() {
        self.isScrollEnabled = false;
        self.isScrollEnabled = true;
        
    }
}

Solution 11 - Iphone

SWift 5+

by using Extension

extension UIScrollView  {
    
    func stopDecelerating() {
        let contentOffset = self.contentOffset
        self.setContentOffset(contentOffset, animated: false)
    }
}

use

    myScrollView.stopDecelerating()
    // your stuff

Solution 12 - Iphone

I have tried this methods in collectionview:

self.collectionView.collectionViewLayout.finalizeCollectionViewUpdates()

Solution 13 - Iphone

I wanted to disable scrolling only when a certain UIView within the scrollview is the source of the touch during the swipe. It would have required quite a bit of refactoring to move the UIView outside of the UIScrollView, as we had a complex view hierarchy.

As a workaround, I added a single UIPanGestureRecognizer to the subview in which I wanted to prevent from scrolling. This UIPanGestureRecognizer will cancelsTouchesInView which prevents the UIScrollView's panGesture from activating.

It's a little bit of a 'hack', but it's a super easy change, and if you're using a XIB or Storyboard, all you need to do is drag the pan gesture onto the subview in question.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBen ZottoView Question on Stackoverflow
Solution 1 - IphoneDavid LiuView Answer on Stackoverflow
Solution 2 - IphonecalimarkusView Answer on Stackoverflow
Solution 3 - IphoneTPoschelView Answer on Stackoverflow
Solution 4 - Iphonefunct7View Answer on Stackoverflow
Solution 5 - IphonebudiDinoView Answer on Stackoverflow
Solution 6 - IphoneXatianView Answer on Stackoverflow
Solution 7 - IphonemvdsView Answer on Stackoverflow
Solution 8 - IphoneJohnny RockexView Answer on Stackoverflow
Solution 9 - IphoneBrownsoo HanView Answer on Stackoverflow
Solution 10 - IphoneStefanLdhlView Answer on Stackoverflow
Solution 11 - IphoneLakhdeep SinghView Answer on Stackoverflow
Solution 12 - IphoneKalerfuView Answer on Stackoverflow
Solution 13 - IphoneDaniel WilliamsView Answer on Stackoverflow