Can One touch handled by Two UIViews? - iphone

Say, I've two overlapping UIView layers:
----view-top
--view-below
When I touch the screen, I want the touch be handled by these two views, not just one.
How can I do that?

Try this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.nextResponder touchesBegan:touches withEvent:event];
}
This will send the touch to the next responder in the chain, in this case, your view!

Related

how to "bypass" touch events in Cocoa-touch?

I want to make a transparent mask-view over the current window, which just tracks touch events and passing them to the visible views below. However if I set userInteractionEnabled=YES to this mask, this blocks the events and won't be passed below.
Is there any way that I can prevent this view from blocking the events, or manually passing the events below?
Thanks,
I just recently did this for one of my apps and it turned out to be quite simple.
Get ready to subclass UIView:
I called my Mask View the catcher view and this is how the protocol looks:
#interface CatcherView : UIView {
UIView *viewBelow;
}
#property(nonatomic,retain)UIView *viewBelow;
#end
Here you are just subclassing UIView AND keeping a reference to the view bellow.
On the implementation you need to fully implement at least 4 methods to pass the touches to the view, or views bellow, this is how the methods look:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Touch Began");
[self.viewBelow touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Touch Moved");
[self.viewBelow touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Touch Ended");
[self.viewBelow touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Touch Cancelled");
//Not necessary for my app but you just need to forward it to your view bellow.
}
Just remember to set the view or views that are bellow when you create the view; it is also very important to set the background color to clear, so it acts as a mask. THis is how that looks:
CatcherView *catchView=[[CatcherView alloc] initWithFrame:[self.view bounds]];
catchView.backgroundColor=[UIColor clearColor];
catchView.viewBelow=myViewBellow;
[self.view addSubview:catchView];
Hope it helps and comment if you need more info.
UIKit determines the target view for an event by sending -hitTest:withEvent: messages down the responder chain
Once the target has been found, the event is sent up the responder chain until a responder that handles it is found (often the view that was touched, but not always)
Thus, if you override -[NSView hitTest:withEvent:] in a suitably high up view (perhaps by using a custom window!) you can note all incoming events and call super to have them behave as normal.

How to enable touch began in UIScrollView?

Am using UIScrollview, when i am trying to capture touch event in UIscrollview is not responding. how should i achieve it? i am using UILable for showing the text.
Yes I was also facing the same problem.But finally I got remedy on it.
Solution is that you will have to create a class inherited from UIScrollview as follows:
#import <Foundation/Foundation.h>
#interface CustomScrollView : UIScrollView
{
}
#end
And override the touches method in its implementation file as follows:
#import "CustomScrollView.h"
#implementation CustomScrollView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.nextResponder touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if(!self.dragging){
[self.nextResponder touchesMoved:touches withEvent:event];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[self.nextResponder touchesEnded:touches withEvent:event];
}
#end
You will have to import this class in the required file and use its object instead of UIScrollview"s object.
Now you can see that control reaches to touches methods in the class in which you have added scrollview whenever you touch on it.
Thanks.
As of iOS 3.2 UIScrollView does not listen to touchesBegan:, touchesMoved:, touchesEnded:, etc. anymore, afaik.
You should add Gesture Recognizers instead to handle touch events in your UIScrollView.
http://developer.apple.com/iphone/library/documentation/uikit/reference/UIGestureRecognizer_Class/Reference/Reference.html
But if you want to handle the touches in one of the UIScrollView's subviews, it would be best to read the Overview section in the UIScrollView documentation. See touchesShouldBegin:withEvent:inContentView:, pagingEnabled, and delaysContentTouches, among others.
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIScrollView_Class/Reference/UIScrollView.html
"split" writes about a solution here that I used in my project to be able to access touches in a scroll view.
No need to go anywhere simple solution is here. Really as simple as you think.

iPhone - how to track touches and allow button taps at the same time?

I'm wondering how to track touches anywhere on the iPhone screen and still have UIButtons respond to taps.
I subclassed a UIView, made it full screen and the highest view in the hierarchy, and overrode its pointInside:withEvent method. If I return YES, I'm able to track touches anywhere on the screen but the buttons don't respond (likely because the view is instructed to handle and terminate the touch). If I return NO, the touch passes through the view and the buttons respond, but I'm not able to track touches.
Do I need to subclass UIButton or is this possible through the responder chain? What am I doing wrong?
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
return NO;
}
//only works if pointInside:withEvent: returns YES.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"began");
[self.nextResponder touchesBegan:touches withEvent:event];
}
//only works if pointInside:withEvent: returns YES.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"end");
[self.nextResponder touchesEnded:touches withEvent:event];
}
Rather then having extra view you can subclass your applications main window and track touches (and other events in it)
#interface MyAppWindow : UIWindow
...
#implementation MyAppWindow
- (void)sendEvent:(UIEvent*)event {
[super sendEvent:event];
if (event.type == UIEventTypeTouches){
// Do something here
}
return;
}
Then set your application window type to MyAppWindow (I did that in MainWindow.xib in IB)

Make a UIScrollView get touch events with a UITextView as a subview

I have a UIScrollView that contains a UITextView (not editable).
I can't make the UIScrollView gets the touch events, UITextView seems to get them and keep them . Any idea how to let UIScrollView gets the touch events?
I want UITextView to still be scrollable vertically (my UIScrollView is scrollable only horizontally).
In your UITextView subclass, do this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.nextResponder touchesBegan:touches withEvent:event];
}
If you want UITextView to handle the touches too, then I believe you can do this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.nextResponder touchesBegan:touches withEvent:event];
[super touchesBegan:touches withEvent:event];
}
but it might result in really weird behavior.

Is there a way to pass touches through on the iPhone?

I have several UIButtons which I use to set the current action when tapping in the main area. I would also like to allow the user to drag from the button directly into the main area and take the same action; essentially, the touchesBegan and touchesMoved should be passed on to the main view when touching the UIButtons, but also should send the button press action.
Right now, I have the touch up inside changing the control. The drag exit calls the touch up inside section to set the control, then calls the touches began section to start the main area touching operation.
However, at this point, the touchesMoved and touchesEnded are obviously not being called, because the touches originated on the UIButton.
Is there a way to half-ignore the touches so they're passed to the main area, but also allow me to set the control first?
I know this question is two years old (and already answered), but nevertheless...
When I tried this myself, the touches were forwarded, but the buttons no longer behaved like buttons. I also passed the touches along to "super" and now all is well.
So, for beginners that might stumble upon this, this is what the code should look like:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self.nextResponder touchesBegan:touches withEvent:event];
}
In the documentation, look for Responder Objects and the Responder Chain
You can "share" touches between objects by forwarding the touch up the responder chain.
Your UIButton has a responder/controller that receives the UITouch events, my guess is that once it has preformed its interpretation of the message it returns - the touch has been handled and disposed of.
Apple suggests something like this (based on the type of touch of course):
[self.nextResponder touchesBegan:touches withEvent:event];
Rather than disposing of the touch event it is passed on.
Sub classed UIButton:
MyButton.h
#import <Foundation/Foundation.h>
#interface MyButton : UIButton {
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event ;
#end
MyButton.m
#import "MyButton.h"
#implementation MyButton
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
printf("MyButton touch Began\n");
[self.nextResponder touchesBegan:touches withEvent:event];
}
#end
No need to subclass either! Simply stick this on the top of your implementation before anything else:
#pragma mark PassTouch
#interface UIButton (PassTouch)
#end
#implementation UIButton (PassTouch)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
[self.nextResponder touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
[self.nextResponder touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
[self.nextResponder touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
[self.nextResponder touchesCancelled:touches withEvent:event];
}
#end