Can I make a UIScrollView only scroll when i interact only with specific places in the view? UIScrollView iPad - iphone

I have a UIScrollView wich contains 2 views the first at offset 0 and the other at offset 800.
I want the user to be able to scroll down but not always, because in the upper view i have another controls tha receive touch input and dragging and sometimes when you are dragging if your touch is just a little bit out of the control the scrollview scrolls and that's very annoying. So i want that the scrollview only scroll in certain zones.

What you basically need is to subclass the UIView that should intercept touches outside it's frame and override it's hit test method.

Related

Difficulty handling touch events with a UITableView

I am implementing a Google+ type iPhone application. The UI consists of a number of screen-sized panels, and the user can move through these panels horizontally by swiping left or right. I am not using a UIScrollView for this, but am instead implementing it as a series of UIViews on top of a master UIView - I override the touches... events for the UIViews and pass them on to the master UIView to handle repositioning the panels.
My code works perfectly as long as each panel is just an empty UIView (or if it only contains controls that don't pick up touch events, like a UILabel). The problem I'm facing is when I try to put a UITableView on one of the panels. Because the UITableView picks up the touch events, this is interfering with my own code that uses the touch events to slide the panels horizontally.
I have tried two approaches, neither of which is working perfectly:
First approach: I subclass UITableView, overriding the touch... events (touchesBegan, touchesMoved, and touchesEnded). In the overrides, I pass the events on to self.nextResponder and then to super. On my table, I also set canCancelContentTouches = NO;. This works somewhat - if I start swiping with a perfectly horizontal movement, the underlying panel containing the table view moves left and right. However, if I begin the process by swiping vertically, the table view begins scrolling up and down and no horizontal movement happens at all until I lift my finger. Also, if I begin swiping horizontally the left-right movement of the panel happens, but until I life my finger no vertical scrolling of the table view is possible (I'm trying to get a solution where vertical movement scrolls the table view and horizontal movement moves the underlying panel left-right). BTW, without the canCancelContentTouches = NO; call, the touch events stop coming altogether as soon as the table view is scrolled even a little bit.
Second approach: I subclass a UIView, set it's background color to transparent, and then place it over top of the view containing the UITableView. In this overlay subclass, I override the touch events and 1) pass them on to the underlying UITableView and then 2) pass the touch events on to the underlying UIView that handles the left-right swiping. With the approach, the left-right panel movement works perfectly. With the table view, unfortunately, the passed-through touch events allow me to click the table view and change the selected row (so I know the events are at least partially going through), but I can't scroll the table view up or down.
Any suggestions for how to do this correctly are welcome.

How do I animate through a bunch of "paged" views in a UIScrollView?

Say I have a bunch of views in a UIScrollView and I want each one to appear on the screen, one at a time, how do I do so?
Assuming your views are screen size, position them next to each other and set the pagingEnabled property to true, make sure the contentSize of the scoll view is wide enough for all of the views and then the user should be able to swipe through them one view at a time. You could do it automatically with an NSTimer if you don't want the user to have to swipe.

Second UIScrollView responding when using a UIScrollView

This is more of a check as I believe this is right but its a lot of work if I'm wrong.
I want to basically achieve fixed positioning with a scrollView. I want to have a list along the top that is always visible, scrolls horizontal only and then a scrollview beneath that to move around the information which scrolls both vertically and horizontally.
I figure I need to subclass UIScrollView and overwrite touchesBegan, touchesMoved and touchesEnded to send the touch to both UIScrollViews.
Is this right or off track?
Cheers
Overriding the touch events on a scroll view is probably not what you want to do. Instead you can simply use a single scroll view, and then in the parent view's -layoutSubviews or in the scroll view's delegate methods you can move the list so it's always at the same vertical position (use the scroll view's contentOffset property to determine where that should be). Both the delegate method and -layoutSubviews is called before the drawing actually occurs after the scroll view scrolls, so by always repositioning your view where you want it to be, it will appear to remain fixed to the user.

How to filter touch events for a UIScrollView?

I have a view that displays a PDF. It should be zoomable, so I also created a UIScrollView, and in its delegate I implemented viewForZoomingInScrollView to return the PDF view. So far so good.
However, when the user reaches the edge of a zoomed PDF page, I'd like to flip to the next page. Sounds easy, yet I can't seem to figure out how to do it.
I've tried some different approaches:
Using scrollViewDidScroll to detect if scrolling has reached the edge. The problem here is that if zoomScale is 1, and therefore scrolling is not possible, then this function is never called. But the UIScrollView still swallows all touch events, so I also can't detect reaching the edge in touchesMoved. Setting canCancelContentTouches to NO when not zoomed is not an option, as that would also prevent zooming in.
Subclassing UIScrollView, and forwarding some of the touch events to the next responder. Unfortunately when UIScrollView detects a drag operation and cancels the touch, touchesMoved and touchesEnded are not called even for the UIScrollView subclass anymore. Again, setting canCancelContentTouches to NO is not good, as that would also prevent some desired UIScrollView functionality.
Creating a transparent view on top of the scroll view (as a sibling of it), so that this view gets all touch events first, and then forwarding some of the touches to the scroll view. Unfortunately the scroll view doesn't respond to these calls.
I can't use touchesShouldCancelInContentView, becasue that doesn't get the actual touches as an argument, and whether or not I want the scroll view to handle the touch event also depends on the properties of the touch event itself (eg. a touch movement in a direction in which we're already at the edge should not be cancelled by the scroll view, but a movement in the other direction could be).
Looks like whatever UIScrollView is doing is not initiated from touchesBegan / touchesMoved, but instead it gets some notifications about the touches way before that. Possibly in some undocumented way that I can't intercept, nor reproduce.
So is there any way to get notified about all touch movements done over a UIScrollView, while still being able to use (when certain conditions apply) the UIScrollView for zooming and scrolling?
Ok, so here's what I did in the end:
Leaving all scrolling and zooming up to UIScrollView, and handling page turning in the UIScrollViewDelegate's scrollViewDidEndDragging:willDecelerate: is almost a solution, except that this function is never called if the whole content is on-screen, so dragging / scrolling is not possible.
Swipes in this case are handled in a ViewController's touchesBegan / touchesEnded functions, but for this to work, we need to make sure that the UIScrollView does not cancel these events. However, in other cases the UIScrollView should be able to cancel touches so that it can do zooming and scrolling.
The UIScrollView should be able to cancel touches if:
Scrolling is possible (and needed) because the whole content doesn't fit on screen (zoomScale > 1 in my case),
OR
The user touched the screen with two fingers, so that zooming in and out works.
When scrolling is not possible, and the user single-touched the screen, then touches should not be cancelled, and touch events should be forwarded to the view controller.
So I created a UIScrollView subclass.
This subclass has a property pointing to the ViewController.
Using the touchesXXX methods I keep track of the current touch count.
I forward all touch events to the ViewController.
And finally, I've overridden touchesShouldCancelInContentView:, and return NO when zoomScale <= 1 and touchCount == 1.

Scroll view touch detection

I have a problem in the touchesMoved handler with a view that is added onto a UIScrollView. I add a number of labels to the scroll view. Each of these labels contain some text and, on swiping my finger on the labels, I have to play a specific file for that text.
If I just add the view onto the window directly, I get all of the touch events in touchesMoved without any problem. When I add my view onto the UIScrollView and then add this to the window, there is some lag in the touchesMoved handler. I am not getting continuous touch points in touchesMoved as with the normal view. As a result, while swiping the finger from the view, it happens that some labels are missed.
Is the problem due to scroll view? The same code runs perfectly in normal conditions (without a scroll view).
Does anyone have any solution to this?
UIScrollView sets a timer on touchDown to be able to know if it should handle scrolling or if it should pass the events on to subviews.
There is a property on UIScrollView for controlling this behaviour:
#property(nonatomic) BOOL delaysContentTouches