Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect if UIScrollView is scrolling

Tags:

ios

I'm looking to detect if (not when) a UIScrollView is scrolling.

i.e.

BOOL isScrolling = myscrollview.scrolling;

How would I go about implementing this? .dragging and .decelerating do not apply when setContentOffset:animated: is used.

like image 551
Jonny Avatar asked Dec 10 '12 07:12

Jonny


People also ask

How can I tell if a tableView is scrolling?

Since a scrollView has a panGesture we can check the velocity of that gesture. If the tableView was programmatically scrolled the velocity in both x and y directions is 0.0. By checking this velocity we can determine if the user scrolled the tableView because the panGesture has a velocity. Save this answer.

Can stack view be scrollable?

Adding a constraint so that the stackview and scrollview have equal widths will remove warnings from interface builder, but then scrolling will be disabled. Scrolling only happens when the content view inside the scrollview is larger than the scrollview!

Is scrollView scrolling?

In Android, a ScrollView is a view group that is used to make vertically scrollable views. A scroll view contains a single direct child only. In order to place multiple views in the scroll view, one needs to make a view group(like LinearLayout) as a direct child and then we can define many views inside it.


3 Answers

EDIT: This method seems to have stopped working since iOS 14. I'll try and see if I can find an alternative method, and I'll update this answer if I do.


This may be a slightly dodgy way of doing it, but I've used it in my code before and it hasn't failed me yet. :)

Swift

let isScrolling = scrollView.layer.animation(forKey: "bounds") != nil

Objective-C

BOOL isScrolling = [scrollView.layer animationForKey:@"bounds"] != nil;

In addition to self.contentOffset the offset of a UIScrollView is stored in the bounds.origin property of the UIView as well (I guess since it's a bit more convenient in lower-level code). When you call [setContentOffset:animated:], it's passing that off to the UIScrollView as a CABasicAnimation, manipulating the bounds property.

Granted, this check will also return true if the shape of the scroll view itself is animating. In which case you may need to actually pull the bounds object out of the animation ([CAAnimation toValue]) and do a manual compare to see if origin itself is changing at all.

It's not the most elegant solution, but I like being able to avoid having to make use of the scroll view delegate whenever possible. Especially if the scroll view in question might be a subclass explicitly vending its delegate as part of its public API. :)

like image 144
TiM Avatar answered Oct 21 '22 08:10

TiM


Not a very clean solution .. but should be the most reliable:

var isScrolling = false

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    isScrolling = true
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if !decelerate { scrollViewDidEndScrolling(scrollView) }
}

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    scrollViewDidEndScrolling(scrollView)
}

func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
    scrollViewDidEndScrolling(scrollView)
}

func scrollViewDidEndScrolling(_ scrollView: UIScrollView) {
    isScrolling = false
}
like image 29
Rok Gregorič Avatar answered Oct 21 '22 07:10

Rok Gregorič


I usually do this by setting a boolean variable in the scrollViewWillBeginDragging: and scrollViewDidEndDragging:willDecelerate: events.

UIScrollView Docs

like image 31
Echilon Avatar answered Oct 21 '22 08:10

Echilon