UIScrollView gets disabled in one direction - iOS - ios

I have a UIScrollView with no vertical scrolling, and on which I force a particular offset (only x) in case the offset tries to become less that that particular offset.
I use setContentOffset:animated: function, with animated argument as YES. The offset is forced correctly.
After I force the offset, 'sometimes' scrolling in the direction opposite to the initial scroll direction gets blocked. Say, I was scrolling with finger pan from left to right, and forced it to some offset, then I can't scroll from right to left anymore.
But the catch is, if I make any tap on the screen, the scrolling starts happening. I am unable to pan, but if I tap the screen, or tap any button, scrolling starts working. If I try to call the button press method programatically after, say 5 seconds of forcing the offset, then it doesn't work. It seems that I need to touch the screen somehow..
I checked the values of contentOffset, contentSize, they seem fine.
PS: there are times when scrollViewDidEndScrollingAnimation: method is not called after forcing the offset, but that is not necessarily the issue.
Edit: Actually, this thing happens when I take the scroll view beyond the threshold offset using my fingers, and keep panning left. At the threshold point, panning stops, but the next time I try to scroll, it doesn't pan. (i.e., I don't give a jerk to go beyond the threshold).
Edit: One more possible loophole: I make scrollEnabled equal to NO just before forcing the new offfset, and just after giving the command to set the new offset, I set it back to YES. I needs to be done so that if I try to scroll the scrollview with a jerk, it doesn't scroll away to the left while trying to set the new offset, since paging is enabled.
Edit: Could it be because I set scrollEnabled to NO while actually scrolling using touch? I do enable it later, but maybe that is some issue...
Important Edit: If I long press on the scrollView, and then try to move, scroll view starts scrolling!
Edit: This code is in scrollViewDidScroll:
if ((theScrollView.contentOffset.x < theScrollView.frame.size.width)
&& [currentlyDisplayedVC isEqual:VC1])
{
//if this is not done, and this call happens when VC3
//is visible a bit too much, scrollView scrolls till VC3.
scrollView.scrollEnabled = NO;
[scrollView setContentOffset:CGPointMake(scrollView.frame.size.width, 0) animated:YES];
scrollView.scrollEnabled = YES;
//this is done so that this block is not reached everytime during scroll animation.
currentlyDisplayedVC = VC2;
}
Then in scrollViewDidEndWithANimation: I add [self VC2reached]

Have you tried using setUserInteractionEnabled:NO and YES to stop/allowing user to interact with the UIScrollView instead of using the scrollEnabled property?

I subclassed UIScrollView and overrode the method touchesShouldBegin:withEvent:inContentView:. In the method I return NO for that particular moment when I see the view stuck, so that all touches are taken in by the scroll view instead of passing them to any other contentView. That solved the problem.
Edit: That doesn't solve the problem actually. I want to disallow touches on contentView ONLY when an attempt to scroll the scrollview is being made, not when some other event like tap on the contentView is attempted. But in ths olution that I posted, all touches will be kept with the scroll view. Do we have a similar touchMoved: method?

Instead of using setContentOffset:animated:
you should try using scrollRectToVisible:animated:

Related

Detect when a user interrupted UIScrollView animation

I have an app with a horizontal scrolling uiscrollview, it shows 3 subviews side by side. I am using Objective C.
When the user drags and releases, the code detects which is the closest subview and automatically scrolls to the nearest of the 3 subviews, making it fully centred.
This all works fine, except;
When the scrollview is animating an auto-centering move, the user can interrupt by just tapping it (not dragging).
This single tap halts the animation and scrollview, leaving it not centred on any of the 3 subviews.
No delegate method I have found can detect when the animation is interrupted and then continue with centering.
How can I do this?
When you start the scroll animation with setContentOffset:animated: or scrollToRectVisible:animated:, its end will be marked by UIScrollViewDelegate method scrollViewDidEndScrollingAnimation:. If before that other delegate method is called, like scrollViewWillBeginDragging: or scrollViewDidEndDecelerating: - that means that user interrupted your animatin with drag (or a tap).
What you want to do is restart your animation when user stops dragging - in scrollViewDidEndDragging:willDecelerate: or scrollViewDidEndDecelerating:
Thanks again mag_zbc!
This really helped me find the solution.
I was overcomplicating the animation, checking for the current position both after the user finished dragging as well as when the animation finished.
To solve it, I just checked the current offset in scrollViewDidEndDecelerating::
-If the final offset was one of the three correct locations (auto-offset finished uninterrupted) then do nothing.
-If the offset was not one of the correct locations (animation was interrupted), then move again.

Often Inadvertently enter one of ScrollView's sub-items when scrolling the ScrollView

When I am scrolling a ScrollView, it's very often that it enters the item of the ScrollView by accident.
How can I solve this problem?
Is it because of the scroll gesture duration?
How can I more clearly identify between the tap-gesture and scroll-gesture?
Update: I finally found it is because I set the sub-item's gesture as "TouchDown" but not "TouchUpInside". So that's my reason.
You should use a UIScrollView property.....which will delay to respond its subitems....
scrollViewObj.delaysContentTouches = YES;
This will respond its sub-items after the scroll of your scrollview finishes.

Very slow deceleration in UIScrollView just in certain cases

I am struggling with aligning a screen to a certain Views inside a UIScrollView. I would like to have same behaviour as paging (same fast and smooth deceleration) but with alignment to a custom views instead of stoping on multiples of the scroll view’s bounds. I have implemented delegate method scrollViewWillEndDragging(_:withVelocity:targetContentOffset:) in order to define my own scroll view’s bounds location. I have also set decelerationRate to UIScrollViewDecelerationRateFast.
It work mostly as desired except the cases when alignment animation is very slow. To be more precise, sometimes, after the dragging is finished, the scrolling animation decelerates to final point very slowly. It finally reach the correct point but after a longer while. I am not able to track down the cases when it happens. I am able to say that everything works fine when final velocity of dragging is zero. Thus, it happens only in some cases when dragging is finished with nonzero velocity.
I wonder if somebody had same problem since I wasn't able to google anything useful. Can you help me please?
I have solved this problem by implementing delegate methods scrollViewDidEndDragging and scrollViewWillBeginDecelerating. Then by using information from scroll view’s pan gesture I found out about translation and I determined final scroll view’s bounds location using setContentOffset method on scroll view.

iOS: How do I allow scrolling only when the user drags the scrollbar?

I have been trying to create a scrollable view using UIScrollView. I want this view to be a scratchpad where I can do rough work with touch gestures.
But, doing a drag gesture makes the UIScrollView move the page.
This is why I want to disable scrolling on gesture and enable scrolling only when I drag the scroll bars on the screen.
I have tried Googling, but haven't found any result so far.
It would be great if you could guide me to a solution or help me with some pointers.
Not sure you can or that it would be usable.
How about enabling scrolling only with 2 fingers? By setting the scroll view pan gesture minimumNumberOfTouches To 2.
Otherwise, think about acting as the delegate of the scroll view pan gesture, specifically for gestureRecognizer:shouldReceiveTouch: so that you can examine the touch position and only allow the gesture to start of significantly close to the edge of the view.
I world recommend using this library: https://github.com/BasheerSience/BRScrollBar
1- Use instance method to add the scrollBar
2- in your UIViewController add these lines of code
// First intit by using the instance method
_brScrollBarController = [BRScrollBarController initForScrollView:self.scrollView
inPosition:kIntBRScrollBarPositionRight
delegate:self];
// show the scrollBar always, do not hide
_brScrollBarController.scrollBar.hideScrollBar = NO;
// disable scrolling for your scrollView
self.scrollView.scrollEnabled = NO;
3- now your scrollView will not respond to gestures, and you will use BRScrollView to scroll by dragging the bar
let me know if you have any questions

Animate while UIScrollView bounces

I want to do a little animation every time the UIScrollView bounces, to be exact, I want a button to move a little bit to the left and then back to it's original position. I use the scrollViewDidScroll method and check if the scrollView's contentOffset is higher than the actual content height and then call the animation. The problem is that the animation is called multiple times during the bounce if I do it like that. Is there a way to only call it once?
Have an ivar or property named something like animationActive that will keep track of animation. When you start it, set animationActive = YES; and when animation completes, set animationActive = NO;. And of course, before you start animation, check if (animationActive == YES).

Resources