Slide of UIScrollView - iphone

I made a slideview using a uiview and detecting touches to move pages. This slideview is almost like this, except that I made it works like a UITableView.
Now I'm using this to uivews with uiscrollviews. The problem is, "how to distribute touch events to scrollview or slideview?". I had the logic to do. Basically, the uiscrollviews are vertical and slideview is horizontal.
I tried hitTest to keep the touchBegan,Moved,Ended in slideview. When I get a touch movement horizontally, I keep to slideview, when vertically, distribute to uiscrollview. But I cannot figure out how to distribute events to uiscrollview.
Calling [scrollView touchesBegan:touches withEvent:event] doesn't work. I supposed uiscrollview has a different way to work.

If you don't find a clue to your answer, probably, you're wrong.
UIScrollView uses a own way to get touchesBegan, Moved and Ended. Way that I don't, but it's mean if you override touchesBegan to make UIScrollView stops to work, you won't get it. Using hitTest in superview of scroll, you can get the touches before UIScrollView but you can't change the touches target while touches is happening.
After all, there is one way to solve this, ashly, three ways.
1- Simulate touches
I didn't test this, you'll know below. Events come from UIWindow and distributed to subview by - (void)sendEvent:(UIEvent *)event. We don't know how touches target is saved, and change this is completely out of question. But we can use the idea of override superview's hitTest to know what the user will do to make a 'WA' to change the target. To do this, simulate a event of touch ended. Supposed target will be reset. Simulate a event of touch begin again, and this time make sure to let hittest get scrollview.
You can find how simulate events here. The problem is, probably your app will be rejected due using private methods.
2- Make your own UIScrollView
This should be the best or the worst, depending what you want to do. I believe it's painful. And isn't what you want to do right now.
3- Surrender to 'Nest UIScrollView'
To make slideshow of pdf, hq, docs and books, it's the best and painless way. Put a UIScrollView inside another and let them reach an agreement of scrolling. http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/UIScrollView_pg/NestedScrollViews/NestedScrollViews.html

Related

Nested UITableViews: a way to scroll both the outer vertical UITableView and a child horizontal UITableView at the same time?

When you're working with an atypical nested UITableViews setup - where you have an outer vertical UITableView that hosts 90° rotated UITableViews (see: Looking for a UI library to present Data horizontaly in iOS ):
is there a way to make iOS process vertical and horizontal touches at the same time?
I found that iOS is very clever in processing touches:
horizontal touches make the relevant horizontal UITableView scroll, while a vertical swipe makes the outer UITableView scroll. Perfect.
Only, I'd love to be able to move my finger diagonally and see the outer UITableView and the inner UITableView scroll at the same time.
I tried a few approaches (playing with canCancelContentTouches, delaysContentTouches, and touch messages) but I haven't found a way to make this happen.
EDIT:
Here's a XCode4 project that shows this behavior: http://marcanton.io/other/stackoverflow/nestedtableviews.zip
EDIT:
I submitted this issue to Apple Developer Technical Support, here's their reply:
Thank you for writing to Apple
Worldwide Developer Technical Support.
I am responding to your inquiry
concerning touch events in embedded
UITableViews.
Typically this is an approach that is
not recommended. The issue is that
UITableView inherits from UIScrollView
and as stated in the documentation for
UIScrollView:
"Important: You should not embed
UIWebView or UITableView objects in
UIScrollView objects. If you do so,
unexpected behavior can result because
touch events for the two objects can
be mixed up and wrongly handled."
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIScrollView_Class/Reference/UIScrollView.html%23//apple_ref/occ/cl/UIScrollView
So that this time, there is not a
workaround for getting both to scroll
at the same time.
I recommend that you file an
enhancement request at
http://developer.apple.com/bugreporter/
detailing what you would like to see
us add in a future release.
Still, I think that there has to be a way to enable this functionality, although I understand that this is not recommended. In fact, Apple does not even recommend hosting UITableViews inside another UITableView, but with the exception made above, it works quite beautifully.
I'll keep this question updated with our collective findings.
EDIT: There actually is a way, detailed here: http://marcanton.io/blog/nested-orthogonal-tableviews/
This would have to be a custom mirroring of intercepted touch events. Touch events follow the responder chain model, which means that if an object in the responder chain (the top most (outermost) view) cannot handle the event or action, it resends the message to the next responder (in this case the background UITableView in the chain). This is why you are seeing the horizontal events go to the horizontal UITableView and the vertical events going to the vertical UITableView. A diagonal touch event has applicable horizontal and vertical events, so the top-most view (the outer vertical UITableView) can respond to the vertical touches and swallows the event.
If you think about it, all vertical touches likely have a little bit of horizontal events (think about when you flick your finger), so there is likely some work done in the background to determine how to interpret the touch event (either as a vertical or horizontal).
I found this tread on passing events down to the next object in the responder chain. You might want to give this a try as a partial solution to your puzzle. The rest is to figure out how to capture the horizontal touch events and pass them along to the next responder.
Interesting, I haven't played around with this kind of setup yet, but I would try to intercept touch events on the nested UITableViews and delegate any vertical movement to the outer UITableView - and vice-versa.

UIScrollView with embedded UIWebView not scrolling after holding

I have a UIWebView which is embedded in a UIScrollView. The webView is resized so that the scroll view manages all the scrolling (I need control over the scrolling).
In the webView I have disabled userSelection via '-webkit-user-select: none;'
Everything is working fine except one annoying detail. When I hold down my finger on the content before starting to scroll for about a second the scrollView won't scroll. My best guess is, that it has something to do with userSelection. The time is about the same it usually takes for the copy/paste/magnifying-thing to appear which usually disables scrolling as well.
I am running out of ideas on how to solve this. Every help would be greatly appreciated!
Thanks!
EDIT: Another aspect of the problem is, that the non-scrolling actually triggers JS-Eventhandler (click, mousedown, mouseup) inside my webView which leads to surprising app behavior. The user puts her finger down, waits, scrolls, nothing happens, removes her finger and this is perceived as a click, which feels wrong from a users perspective.
I would guess what is happening is that after that short duration, the scrollview is no longer interpreting the touch as being on it's view and instead passes the touch down to it's content views.
Have you tried delaying the content touches for the scrollview? This will essentially tell the scrollview to delay taking action on the touch event and instead to briefly monitor the touch and if the touch moves then it recognizes it as a swipe gesture for scrolling. If it doesn't move, it will eventually pass the touch along to it's subviews.
scrollView.delaysContentTouches = YES;
I think even then, there is a standard delay time before the scrollview will pass the touch events along the responder chain. If you hold for too long, it's going to naturally perceive it as being a press down event rather than a scroll event.
This question is not relevant anymore. As of iOS 5.0 the UIWebView is based on a real UIScrollView and also exposes that UIScrollView via a property. Use that instead.
And don't mess with UIWebViews embedded in UIScrollViews anymore. The documentation explicitly advises against that.
Relevant Documentation

iPhone - Catch horizontal swipes -before- subview

I have a view, that is able to go back to the previous view.
Let's say this is a questionnaire. So my main view is the questionnaireView(Controller), and it has a subview which shows a question with 2 possible answers. When one answers the question, one presses next, and the questionnaireView(Controller) shows the next question in that particular subview. Simple, right?
Okay, now imagine having to accomodate up to 10 anwers for a particular question. This will require implementing a scrollview in the subview, to accomodate for the question + all answers.
Now my question: I want questionnaireView(Controller) to receive notice of horizontal swipes (next/previous question), but I want all other touches (taps, for the radiobuttons of the answers, and vertical swipes for the scrollview) to go through...
Any idea's how to go about this? I have tried about 5 different approaches and broke my head and motivation on each on of 'em :/
Last one (and most simple one), was simply adding another subview to questionnaireView(Controller), overlaying the question+answer view.
This kindly catches all the touchesBegan/Moved/Ended/Cancelled for me, but even if I just put a forward in -each- of thoses methods ([self nextResponder] ...) the underlying view (with the answers, and the scrollview) won't respond anymore...
I'm kinda lost on this, and am thinking of writing my own Scrollview someday, since UIScrollView is the most terrible monster faced by iPhone devvers :P
Mind you, I am supporting iPhone OS 3.0 and up, so the new gesture APIs are no-go.
I'm not sure what you mean by "a forward in -each- of thoses methods". I'm not sure that nextResponder is the correct thing to forward them to either.
The problem is that touches are supposed to be "owned" by a single view throughout their lifetime. I'm not sure how UIScrollView or gesture recognizers are implemented, but I'm pretty sure they do more than you're supposed to do on your own.
I'd override questionnaireView's hitTest:withEvent: to return self. In your touchesBegan:withEvent:, call [super hitTest:[touch locationInView:self] withEvent:event] and store the subview that "owns" it. In touchesMoved:withEvent:, forward the touch to the relevant subview, but if you detect a gesture, "forget" the subview that owns the touch and instead call touchesCancelled:withEvent:. In touchesEnded/Cancelled:withEvent:, forward it to the subview and then forget the owning subview.
It's icky, but it mostly works. Some things it gets wrong (from the perspective of subviews):
-[UIEvent touchesForView:] will return the QuestionnaireView.
UITouch.view will return the QuestionnaireView
UITouch.phase might not be UITouchPhaseCancelled in touchesCancelled:withEvent: (if you detect the gesture and cancel the touch).
*

Detect number of fingers in UIScrollView swipe

Questions similar to this have been asked all over, but I haven't been able to find a solution to my specific problem, so here goes.
I have a UIViewController with a UIScrollView in its view. Within the scrollview, I have a number of regular uiview subviews. I want to be able to detect whether the scrollview swipe was with one or two fingers, and to cancel the scroll and call some other method in one of those cases. Can anyone help me with this?
If you are on OS 3.2 + try giving UIGestureRecognizer a try. You can detect swipes of any number of fingers very easily.
http://developer.apple.com/iphone/library/documentation/uikit/reference/UIGestureRecognizer_Class/Reference/Reference.html

How to make UITableView(Controller) catch multitouch events?

I have a subclass of UITableViewController that works as expected. I'd like to capture multitouch events for the whole table to do something with them.
The way I understand it, I should make the tableView of the controller be a subclass of UITableView. In that class I could capture the touchesMoved etc events.
But I also understand that UITableView is a subclass of UIScrollView which hijacks all the touch events so that I never see them.
So, is there some way to still get to those multitouch events for my table? Specifically I'd like to implement something like two-finger pinch/zoom and one-finger horizontal dragging.
Since those touch events are all passed to table cells, perhaps I should do this at table cell level? The only question there is, is this compatible with multitouch? (So that I can aggregate events from different cells as multitouch events and process those...)
EDIT: tried with cells and was able to see some horizontal events. All the vertical events, though, are completely hijacked by the UIScrollView as table scrolls. I wouldn't want to hack this if there's any way at all to make the UIScrollView un-hijack these events...
This solution seems to work fine and feels quite clean. I'll leave the question open for a while, for if someone wants to suggest something else, and then mark this as answer at some point if I won't get anything more.
EDIT: this answer is obsolete, since the modern way to do this, of course, is UIGestureRecognizers.