Event scrolling (scrollViewDidScroll) never called - Swift 3
You just have to add the delegate to your viewDidLoad()
func:
override func viewDidLoad() {
super.viewDidLoad()
//add this line
self.scrollView.delegate = self
}
My scrollViewDidScroll function is not receiving calls
Add the scrollview delegate. Whenever you implement a delegate method you need tell it what controller to use, usually it will be self
. It's caught me out a few times.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
scrollViewer.delegate = self
}
UITableViewController scrollViewDidScroll: not called during cell removal
Well, after reading your question a few times, it looks like our issues aren't the same.
I believe your issue is because scrollViewDidScroll: is not called during some animations. You should see this answer here, though unaccepted (maybe because they imply user interaction is the only way to trigger it), it also contains a path to this answer about getting scrolling events during automated animations which may be of help.
Swift UIScrollViewDelegate not triggers scrollViewDidScroll event
how about you assign the delegate this way?
class NavigationScrollView: UIScrollView{
override func didMoveToSuperview() {
super.didMoveToSuperview()
self.delegate = self
}
}
class ContentScrollView: UIScrollView{
override func didMoveToSuperview() {
super.didMoveToSuperview()
self.delegate = self
}
}
How to detect when a UIScrollView has finished scrolling In Swift
The delegate method tells you when finished
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
self.stoppedScrolling()
}
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
self.stoppedScrolling()
}
}
func stoppedScrolling() {
println("Scroll finished")
}
How to detect when a UIScrollView has finished scrolling
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self stoppedScrolling];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (!decelerate) {
[self stoppedScrolling];
}
}
- (void)stoppedScrolling {
// ...
}
scrollViewDidEndScrollingAnimation not called
Is this what you need?
Add these funcs to your table view controller...
Edit: forgot to include the scrollViewDidEndScrollingAnimation
...
override func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
scrollingFinish()
}
override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
scrollingFinish()
}
override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
scrollingFinish()
}
}
func scrollingFinish() -> Void {
print("Scroll Finished!")
}
How to avoid a double call of scrollViewDidScroll() method while swiping the collectionView?
Add a Bool var to your OnboardingViewController
:
var programmedScroll: Bool = false
then, when prev or next button is tapped, instead of:
@IBAction func prevButtonPressed(_ sender: UIButton) {
if currentPage != 0 {
currentPage -= 1
let indexPath = IndexPath(item: currentPage, section: 0)
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
do this:
@IBAction func prevButtonPressed(_ sender: UIButton) {
if currentPage != 0 {
currentPage -= 1
let indexPath = IndexPath(item: currentPage, section: 0)
// instead of this
//collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
self.programmedScroll = true
UIView.animate(withDuration: 0.3, animations: {
self.collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: false)
}, completion: { _ in
self.programmedScroll = false
})
}
}
Now your scrollViewDidScroll
won't be called during that animation.
Edit
In scrollViewDidScroll
implementation:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if !programmedScroll {
let visibleRectangle = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
let visiblePoint = CGPoint(x: visibleRectangle.midX, y: visibleRectangle.midY)
currentPage = collectionView.indexPathForItem(at: visiblePoint)?.row ?? 0
}
}
Edit 2
Using the above approach resulted in a less-than-acceptable scroll effect, because a UICollectionView
only renders cells that will be displayed.
When telling the collection view to .scrollToItem
with animated: false
, the collection view immediately drops the rendering of the cell that will no longer be visible.
So, we'll take the same approach, but find another way to "re-enable" the scrollViewDidScroll
code after a Next / Prev button has called .scrollToItem
.
In prev/next, let's still set self.programmedScroll = true
, but instead of the animation block let's use the built-in animation:
@IBAction func prevButtonPressed(_ sender: UIButton) {
if currentPage != 0 {
currentPage -= 1
let indexPath = IndexPath(item: currentPage, section: 0)
// disable scrollViewDidScroll code execution
self.programmedScroll = true
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
@IBAction func nextButtonPressed(_ sender: UIButton) {
if currentPage == slides.count - 1 {
//hide onboarding
} else {
currentPage += 1
let indexPath = IndexPath(item: currentPage, section: 0)
// disable scrollViewDidScroll code execution
self.programmedScroll = true
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
then we need to "re-enable" the code to change the page control dot mid-way between cells when dragging, so we'll implement:
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
// re-enable execution of scrollViewDidScroll code
programmedScroll = false
}
That should do it. I updated the repo at: https://github.com/DonMag/TestCollectionViewOnboarding
UIScrollView is not scrolling despite setting delegate
Problem is with these two lines of code
self.scrollView = UIScrollView(frame: CGRect(x: 0, y: displayHeight - displayHeight / 3, width: displayWidth, height: displayHeight))
self.scrollView.contentSize = CGSize(width: displayWidth, height: displayHeight)
Either the scrollView.frame.size
should be smaller or the contentSize
should be larger. If both are same, the scrollView has no need to scroll.
If only the heights of frame and content size are different, you'll get vertical scroll. if it is the widths, you get horizontal scroll.
Related Topics
Type 'Bundle' Has No Member "Module"
How to Create a Cocoapod with .Swift
Is There Any Difference at All Between Suffix(From:) and Dropfirst(_:)
Cannot Convert Value of Type 'X' to Expected Argument Type 'X'
Member Operator '==' Must Have at Least One Argument of Type
Geocodeaddressstring Not Working for Swift
Swift Combine How Set<Anycancellable> Works
Destructuring Tuple of Tuple in Closure
Count Number of Instances of a Class Swift
How to Cast Sockaddr_In to Sockaddr in Swift
Sknode Subclass Generates Error: Cannot Invoke Initializer for Type "X" with No Arguments
Swift Navigation Bar Item Not Calling Action
Implement Protocol with Different Associated Type
How to Define a Variable in a Swift If Statement
Filtering Realm Objects with Swift
How to Convert Custom Object to Data Swift
Can't Upload .Ipa from Xcode 8, "The Info.Plist Indicates a iOS App, But Submitting a Pkg or Mpkg."