What is difference between scrollViewWillBeginDecelerating: and scrollViewDidEndDragging:willDecelerate:? - ios

scrollViewWillBeginDecelerating: delegate method is called on finger up as it is moving.(from UIScrollView.h)
But, scrollViewDidEndDragging:willDecelerate: delegate method is also called when same state.
(called on finger up if the user dragged. decelerate is true if it will continue moving afterwards) -> from UIScrollView.h)
When I test, they are always called together.
I don't know what is the difference.
Actually, I should know when a scroll will be begun deceleration.
scrollViewWillBeginDecelerating: is always called on finger up.

No both has differrent states
scrollViewDidEndDragging - The scroll view sends this message when the user’s finger touches up after dragging content. The decelerating property of UIScrollView controls deceleration.
scrollViewWillBeginDecelerating - The scroll view calls this method as the user’s finger touches up as it is moving during a scrolling operation; the scroll view will continue to move a short distance afterwards. The decelerating property of UIScrollView controls deceleration.
Refer Here

If you drag the scroll view so slowly that after your finger is up, the scroll view won't move, then scrollViewDidEndDragging:willDecelerate: will be called, with decelerate == NO, while the scrollViewWillBeginDecelerating: not being called.
Both the delegate methods will be called when you drag fast enough.

Related

UIKit collection view, strange behavior (accessing/scrolling cells)

So I recently implemented a collection view in my app, and I got a bug that I can't seem to solve, searched it and saw no threads about it.
If I have my cursor/finger over the cells i can't scroll through my collection view i need select a "empty" area to scroll.
Second strange Behavior I came across is that I can't directly touch a cell. I need some sort of swipe gesture over it to trigger the code when a cell is selected.
If I go to my collection view on my storyboard and select Delays Content Touches and Cancellable Content Touches in the scrollview section, the collection view scrolls just fine but if I put my finger/cursor over a cell with these option enabled I can't access any cells anymore.
This completely confuses me.
and thank you for reading/considering this thread.
Let's see what your two properties do.
delaysContentTouches: If the value of this property is true, the scroll view delays handling the touch-down gesture until it can determine if scrolling is the intent. If the value is false , the scroll view immediately calls touchesShouldBegin(_:with:in:). The default value is true.
canCancelContentTouches: If the value of this property is true and a view in the content has begun tracking a finger touching it, and if the user drags the finger enough to initiate a scroll, the view receives a touchesCancelled(_:with:) message and the scroll view handles the touch as a scroll. If the value of this property is false, the scroll view does not scroll regardless of finger movement once the content view starts tracking.
First, you set delaysContentTouches to false. So the scrollview immediately calls the content view's touch handling methods, allowing it to handle the touch. Obviously, the scroll view won't start scrolling right away because of this, even if you drag.
Second, you also set canCancelContentTouches to false. But if the scroll view isn't allowed to "take over" touches that the content already handles (by cancelling them), it is never able to start scrolling later on either. So if your touch hits a content view, there is no possible way for the scroll view to start scrolling: it isn't allowed to scroll right away because it isn't allowed to delay the content touches, and it can't start scrolling later because it can't cancel the content touches.
I don't know what happens within your cells, not sure what code you put in there. However, you should probably allow your tableview to both delay touches (that means that your cell won't handle swipes that are cancelled immediately anyway because they were intended to be scroll gestures), and to cancel content touches (that means that when you touch down and don't release, you can still start a scroll gesture after a cell became highlighted).
i had the same problem when touching a cell, the problem was that I'm using more than one UIGesture without adding ".cancelsTouchesInView = false" for each one
so if you're using a UIGesture just add Your_Gesture.cancelsTouchesInView = false
and you should be able to access your cells

Swift: How to override a method for a scrollView?

I'm trying to override the touchesShouldCancel method for a subclass of a scrollview.
This is my subclass code:
class MyScrollView: UIScrollView {
override func touchesShouldCancel(in view: UIView) -> Bool {
print("Works")
return false
}
}
I have made a scrollview of this class and it scrolls it just doesn't ever print "works". I would like to add some functionality to this but it's never being called. According to the apple documentation:
'The scroll view calls this method just after it starts sending tracking messages to the content view.'
This makes me believe the method should be called whenever I am scrolling and I can't figure out why it's not. Cheers if anyone has any ideas.
From the docs:
Because a scroll view has no scroll bars, it must know whether a touch signals an intent to scroll versus an intent to track a subview in the content. To make this determination, it temporarily intercepts a touch-down event by starting a timer and, before the timer fires, seeing if the touching finger makes any movement. If the timer fires without a significant change in position, the scroll view sends tracking events to the touched subview of the content view. If the user then drags their finger far enough before the timer elapses, the scroll view cancels any tracking in the subview and performs the scrolling itself. Subclasses can override the touchesShouldBegin(_:with:in:), isPagingEnabled, and touchesShouldCancel(in:) methods (which are called by the scroll view) to affect how the scroll view handles scrolling gestures.
Do this experiment.
Add a subview to your scrollview that intercepts touches (think UIButton, not UILabel).
Make sure your content is actually scrollable
Press down on the button and wait for just a moment, then start sliding your finger.
When you tap down on the scroll view and start dragging right away, it assumes you want to scroll the scroll view and not interact with the button.
However when you do that slight pause, it wants to determine if you're trying to interact with the scroll view or with the button.
touchesShouldCancel will then fire.

Restrict angle of swipe to scroll UIScrollView

I have a vertical scroll view that needs to be scrollable but I want to use the left and right swipe gestures for something else. I have the behavior for each swipe direction working, but I want to restrict the angle of a swipe that scrolls the UIScrollView, so that it has to be really, really vertical, and most left or right leaning swipes activate the other behavior and do not change the scroll position.
I know that I can get the swipe angle by overriding scrollViewDidScroll and comparing the previous and current contentOffset, but I cannot stop the scrollview from scrolling there.
How can I limit the angle of a swipe that scrolls a UIScrollView ?
I think scrollViewDidScroll is too late for what you want to achieve.
Maybe try setting the directionalLockEnabled property of the UIScrollView to YES.(not sure if this helps... but play with it)
And/Or implement the UIScrollViewDelegate method - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView and within this methods implementation grab a pointer to the panGestureRecognizer (readonly) property of the UIScrollView passed in.
From there call translationInView: on the UIPanGestureRecognizer, passing in the view in whose coordinate system the translation of the pan gesture should be computed, and with the CGPoint returned use trigonometry to calculate the angle and if it's not within predetermined limits call setTranslationInView: on the UIPanGestureRecognizer to restore.

how to response to touchupinside event in a UIScrollView?

I have a UIScrollView in the centre of the whole view which is separated in to three parts and scroll horizontally.
Users can scroll the view freely and when the finger is up, i want to set one of the three parts to show based on the contentoffset of the UIScrollView.
how could i detect the touchupinside event in the UIScrollView? I tried add UITapGestureRecognizer and override touchesEnded but it does not work.
How about instead using the - scrollViewDidEndDecelerating:?
Keep in mind that just because the user has picked up their finger doesn't mean that the scrollview has stopped changing its content offset. By utilizing the - scrollViewDidEndDecelerating: delegate method, yo will be notified when the scroll view has come to a stop and at that point you can check the contentOffset and do what you need.
- scrollViewDidScroll: isn't a good match for what you want as it gets called even while the user's finger is still down. If that is important to you, then use - scrollViewDidEndDecelerating: as I mentioned above. If you'd rather know when the finger is lifted, and don't care that the scrollview is still in transit, then you can use - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate.

Disable taps on UIScrollView

I would like to disable the effect of the UIScrollView, that it cancels the current setContentOffset animation when tapped. However, panning should still be recognized at any time.
The reason is that I have implemented custom page-sizes (By using the UIScollView delegate's method - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset, where I set targetContentOffset, such that it is a valid page bound).
If a user now taps while an animation is going on, the UIScrollView cancels the animation, which I want to avoid, because it leaves the UIScrollView with an invalid contentOffset.
There's a UIScrollViewDelegate method, scrollViewDidEndScrollingAnimation:, which tells you when a scroll view animation caused by calling setContentOffset:animated: completes. I ended up setting scrollEnabled to NO on the scroll view before I call setContentOffset:animated, then setting it back to YES in scrollViewDidEndScrollingAnimation:. Effectively the user can't tap to cancel the scroll animation.

Resources