How can I force a UIScrollView
in which paging and scrolling are on to only move vertically or horizontally at a given moment?
My understanding is that the directionalLockEnabled
property should achieve this, but a diagonal swipe still causes the view to scroll diagonally instead of restricting motion to a single axis.
Edit: to be clearer, I'd like to allow the user to scroll horizontally OR vertically, but not both simultaneously.
I might be gravedigging here, but I stumbled onto this post today as I was trying to solve the same problem. Here's my solution, seems to be working great.
I want to display a screenful of content, but allow the user to scroll to one of 4 other screenfuls, up down left and right. I have a single UIScrollView with size 320x480 and a contentSize of 960x1440. The content offset starts at 320,480. In scrollViewDidEndDecelerating:, I redraw the 5 views (center views and the 4 around it), and reset the content offset to 320,480.
Here's the meat of my solution, the scrollViewDidScroll: method.
This works for me everytime...
For those looking in Swift at @AndreyTarantsov second solution its like this in code:
what we are doing here is to keep the current position just before scrollview gets dragged and then check if either x has increased or decreased compared to the current position of x. If yes, then set the pagingEnabled to true, if no (y has increased/decreased) then set to pagingEnabled to false
Hope that is useful to new comers!
From the docs:
"the default value is NO, which means that scrolling is permitted in both horizontal and vertical directions. If the value is YES and the user begins dragging in one general direction (horizontally or vertically), the scroll view disables scrolling in the other direction."
I think the important part is "if... the user begins dragging in one general direction". So if they begin dragging diagonally this doesn't kick in. Not that these docs are always reliable when it comes to interpretation - but that does seem to fit with what you are seeing.
This actually seems sensible. I have to ask - why do you want to restrict to only horizontal or only vertical at any time? Perhaps UIScrollView is not the tool for you?
I used following method to solve this problem, hope it helps you.
First define following variables in your controllers header file.
startPos will keep the contentOffset value when your delegate receives scrollViewWillBeginDragging message. So in this method we do this;
then we use these values to determine users intended scroll direction in scrollViewDidScroll message.
finally we have to stop all update operations when user end dragging;
Need to reset
_isHorizontalScroll
to NO intouchesEnded
andtouchesCancelled
.