How to transmit UIEvent to UIResponders below - iphone

I have many small UIButtons and a large one that covers them all.
The small UIButtons should all react to UIControlEventTouchDownRepeat and call a selector. The big UIButton only has to react to UIControlEventTouchDragInside. The big UIButton however, consumes all touches, and the UIControlEventTouchDownRepeat event doesn't reach the small buttons underneath. How can I solve this?

If the big UIButton is covering the small buttons than the short answer is you can't. Events are passed up the responder chain and when it comes to views the events is passed along to its superview unless the event is handled. Since a view only can have one superview what you want to do is not possible, at least not easily.
If you can reverse the layout, having all the small buttons on top of the the big button it could work. I'm not sure if the events would behave as you would like, you just have to test it out. But all the events not handled by a small button should be passed along to the big button.
If you can capture the point that was touched for UIControlEventTouchDownRepeat then you should be able to find which small button is below the touch and pass along the event that way. You would have to ask the superview of the small buttons, which perhaps is the same as the superview for the big button?, for the view at the touched coordinate and the do something to that view.
Possibly you would want to look into an alternative solution, perhaps creating a custom control that handles the touches as you want.

Related

Rearrange subviews in UIScrollView like App-Icons on Home-Screen

Hej folks,
I got a question to you: I got a UIScrollView in my application containing numerous subviews (all direct subclasses of UIView). Now I want to give the user the possibility to rearrange these subviews inside the scrollview. Is there anyway to make it look like the way we all can change the icons on our homescreen (auto-rearrange)? I would really appreciate any help!
Thanks in advance,
Tim
Unless you use some custom tool kit (I'm not sure there exists a custom tool kit or API to achieve this), I think you should create them from scratch.
I'm also creating very similar thing you said. In an UIScrollView instance, I added small subviews and can order them only vertically by dragging. Also, I can take any subview to the outside of an UIScrollView instance. (a little bit tricky)
There are two ways to build them. (small subviews == icons)
1a) Implement touch events(gestureRecognizer or touchesBegan, Moved, Ended, Canceled) in a main subview of UIScrollView that contains many small subviews.
1b) Implement touch events in each small subview.
I chose 1b because I want to use small subviews not only in UIScrollView but also anywhere in my program. But with 1b, it was a little bit hard to prevent multitouch among these small views. Also I felt that with 1b, touch events in small subviews are more free from the complicated responder chains of an application.
2) Create a NSMutableArray instance that contains a list of small subviews.
3) Implement a function that displays a NSMutableArray instance onto a main view of an UIScrollView instance by enumerating it.
4) Implement a function that enumerates a NSMutableArray instance and checks whether a current touch position of small subview is in a frame of any small subview of a NSMutableArray. (or checks whether a current moving small subview's frame interesects a frame of any small subview) You can use CGRectContainsPoint or CGRectContainsRect functions from CGGeomtery.
5a) If yes, then you can just change frame of every small subview of a NSMutableArray.
5b) If the user releases a finger outside of frame of any small subview, then do nothing.
Simply using block-based animation methods(iOS4 and later) or begin/commit animation methods, you can create them like a home screen.
Very Good Example For Scrollview with Pagecontrol like iphone home Screen
https://github.com/jarada/myLauncher

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

How to intercept touch events globally?

I have an view which is sometimes covered by some other views. However, if the user slides the finger across the screen, I want to slide that underlying view across the screen, too.
I could start making custom views for all those covering subviews and forward all kinds of touch events, but that's somewhat cumbersome. Maybe there's some kind of notification or another way that a UIView or UIControl subclass can be aware of touch events happening right now, no matter where they are.
In short: I need an UIView subclass or UIControl subclass which knows about any touch events happening on the entire screen. Or at least if tht's not possible, knowing about any touch events happening above itself in the same underlying superview.
Another description: There are 20 views, all reside inside the same superview. The first view is covered by 19 others. But if the user slides across the screen, that first view must slide too, so it must be aware of touch events.
Is there any better solution that making all 19 views forward touch events? (yes, all 19 views respond to touch events in this example)
Perhaps the hitTest:withEvent: method of UIView will help, it's helped me achieve what you are trying in the past.

Drag & sweep with Cocoa on iPhone

I'm about to start a new iPhone app that requires a certain functionality but I'm not sure if it's doable. I'm willing to research but first I just wanted to know if I should at least consider it or not.
I haven't seen this in an app before (which is my main concern, even though I haven't seen too many apps since I don't own an iPhone), but an example would be the iPhone shortcuts panels: you can hold on an app, and then drag it to another panel, sweeping while still dragging it. But this is the core app, is it possible to reproduce something similar within a normal app?
I only need to be sure it can be done before I start digging, I don't need code examples or anything, but if you have some exact resources that you consider helpful, that would be appreciated.
Thanks!
Yes. If you have your custom UIView subclass instance inside a UIScrollView, your view controller just needs to set the UIScrollView to delay content touches and not allow it to cancel touch events.
[scrollView setCanCancelContentTouches:NO];
[scrollView setDelaysContentTouches:YES];
When the user taps and holds in the custom view, the event goes to that custom view, which can process the touch events to drag an item around, but if the user quickly swipes, it scrolls the view.
The "panel" view that you're referring to appears to be a UIPageControl view — although, perhaps, the specific incarnation of this view that Apple uses for the iPhone's home page may be customized.
Instances of generic UIView views that you might touch-and-drag will receive touch events. By overriding methods in the view, these events can be processed and passed to the page control, in order to tell it to "sweep" between pages.
If I wanted to do what you're asking about, that's how I might approach it. It seems doable to me, in any case.
Start with this: Swip from one view to the next view
Try using a UIButton that tracks the time since the state of the button changed to "highlighted". You may need to do this in order to track the dragging and move the button around:
Observing pinch multi-touch gestures in a UITableView
Check to see if the button starts overlapping one side of the screen while being dragged. If s certain amount of time elapses since the button first started overlapping the edge and then manipulate the UIScrollView so that it switches to the next page on the corresponding side of the screen
You may need to use NSTimer to keep track of how long the button is held down, etc.
In any case there's no reason why this couldn't work.
If UIButton doesn't work then perhaps try a custom subclass of UIControl (which tracks the same touch down actions etc.). If that doesn't work then use the window event intercept thing to track everything.

Cocoa touch view with multiple identical subviews

I'm having my first foray into Cocoa Touch programming (and one of my first into Cocoa in general) and writing a simple game for the iPhone, though this question is about cocoa touch in general.
The main UI consists of a strip of identical acting buttons (only varying in colour) arranged horizontally across the screen. Although they act like buttons they need to have a custom drawn appearance. Each responds to touch events in the same way, triggering other events in the application.
I want to define a custom view, partly to have more control over the behaviour than just having a bunch of standard buttons, and partly to learn more about cocoa programming.
Should I define a main view with an array of subviews each of which draws itself and forwards touch events? Each button should do standard things like show a pressed state when touched and so on. Are there any pre-existing container views for this kind of scenario?
Or should I just define one main view which draws the whole strip and detects where a touch occurs? I feel this is a badly engineered approach - I shouldn't be programming hit test code.
Edited to clarify the question
The more lightweight approach is to add sublayers to your UIView's layer. Use hitTest: to dispatch touches you receive on you UIView to the CALayer instance that needs to receive it.
If you need more of the UIResponder behavior (touchesBegan etc.), you might want to go with subviews instead of sublayers as that would allow you to handle the events directly in the objects rather than having to dispatch them from a central responder (your main UIView).
Consequently, the essential bit may be just how much of the behavior associated with your individual buttons should be known (handled) by the your main UIView. If it makes sense to have everything controlled from a central place, you can put all the logic in the UIView and just use sublayers for lightweight display purposes. If it makes more sense to put the behavior into the buttons themselves, they shoudl be UIResponders and as such subclass UIView and be added as subviews of your main view.
You should use an array of subviews - that way each "button" class knows how to draw itself and its superview (your stated "main view") places the buttons where they need to go.
And second on the NDA: just talk about the iPhone.
If you have a lot of buttons and want to do fancy things with them, I recommend using layers. Your UIView will handle interpreting which layer had the touch (hit testing) and
respond appropriately. If all you're doing is managing a whole bunch of buttons with various effects and animations, this might be an easier route.
As for bad engineering, not at all. If you take a look at the associated guides, you'll see core animation and layers does require hit testing (though that's relatively easy), but it's far cleaner than the UIView doing all the drawing and more efficient than many subviews. It slips right between those two approaches nicely.
Full disclosure: I'm just wrapping my head around how to best leverage this stuff myself, but for more complicated interactive controls.
You can layout your view in Interface Builder. Simply drag a bunch of UIButtons in your view controller's view.
To respond to events, you define an IBAction in your view controller and connect the buttons to it.
This is all very basic. I really suggest that you at least walk through the iPhone programming introduction that Apple has online. It will teach you iPhone and Interface Builder basics.