Touches method in UIViewController and UIView - ios

I'm working on iPad app. My UIViewController contains only a custom UIView with a size of 500wx500h.
I implemented the touches methods both in the UIViewController and the custom UIView in order to call the UIViewController touches methods when we touch all around the custom UIView and call the custom UIView touches methods when we touch inside it.
UIViewController touchesMoved :
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self.view];
NSLog(#"TEST"); // Added during edition
if (!CGRectContainsPoint(self.drawingView.frame, point)) {
NSLog(#"UIVIEWCONTROLLER");
}
}
Custom UIView touches Moved :
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"CUSTOM VIEW");
}
When I'm touching the custom UIView moving my finger, CUSTOM VIEW is logged until I removed the finger on the screen. On the other hand, when I'm touching outside of the custom UIView, the UIVIEWCONTROLLER is called only one time in the touchesMoved method.
Am I missing something wrong ?
EDIT : I added a log in my UIViewController touchesMoved method. When I touch inside the custom view, it logs the TEST during all the touching phase. But when I touch outside, I get the same behaviour.

add exclusiveTouch property to your view to disable multi touches
your view.exclusiveTouch=YES;

There is some likeliness that your self.view is intercepting touches and handling them, so they will not make it through to the view controller. You could try doing either of 2 things (or both) and see if it works:
self.view.exclusiveTouch = NO;
self.view.userInteractionEnabled = NO;
I would also try to call [super touchesMoved: touches withEvent: event];
Hope it helps.

Related

Handling Touch Events Of A UIView That Contains A UIButton

I'm not able to capture touch events from a UIView with a UIButton subview. the UIButton probably prevents the touchesBegan and touchesEnd events from reaching the outer view.
How can I handle those events? I tried setting UserInteractionEnabled to false. The touch event reached the outer view but the UIButton does not transition to highlighted state with this solution.
Is there a way to accomplish this without losing the natural behavior of the button?
(P.S. I do not want to use GestureRecognizers etc. because I need to get the actual timestamp of the event)
If I have understood your question, you can try this approach:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
if (CGRectContainsPoint(yourbutton.frame, [touch locationInView:self])) { //if touch is beginning on Button
}
}

Detect when a view is tapped on

I have multiple Views inside a ViewController and I want to know when a view is tapped on and I'm not sure how to go about it
In order to check whether certain view inside another view was touched you can use hitTest.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
In your custom implementation of touchesBegan check every touch in touches set. The point for hitTest method can be obtained using
- (CGPoint)locationInView:(UIView *)view;
method, where the view is your superView (the one that contains other views).
EDIT: Here's a fast custom implementation:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint locationPoint = [[touches anyObject] locationInView:self];
UIView* viewYouWishToObtain = [self hitTest:locationPoint withEvent:event];
}
I hope this was helpful, Paul
Sources : Detect if certain UIView was touched amongst other UIViews

iOS - how to forward touches to the underlying uiview

I have 3 UIViews of the same size stacked on top of each other. The topmost is transparent and only used for detecting touches. The type of touch detected will determine which of the other two underlying views I want to receive the touch events. Once the topmost view is finished with the touch, I need to forward the touch events to the correct underlying view. How can I do that?
EDIT - I am adding my touch detection code. This is within MainViewController, whose view contains all 3 subviews.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
if (touch.view == self.touchOverlay) {
CGPoint touchLocation = [touch locationInView:touch.view];
//do a bunch of math to determine which view should get the touches.
if (viewAshouldGetTouches) //forward to viewA
if (viewBshouldGetTouches) //forward to viewB
}
}
}
Make your two subviews setUserInteractionEnabled:NO and handle all touches in the parent. Then, depending on touch type, send the correct view a programatic touch event. Then you don't need your clear view on the top. Basically you will be coordinating touch events from the bottom up instead of going top->bottom->middle.
You'll have to do this by creating a UIView subclass for your top view and overriding the following method :
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
// UIView will be "transparent" for touch events if we return NO
return (point.y < MIDDLE_Y1 || point.y > MIDDLE_Y2);
}

UITextField: force resignFirstResponder when tapped outside of it

I have a static UITableView that contains a number of UITextFields. When the user taps outside of any of the text fields I'd like to I'd like to dismiss the keyboard.
At the top level of my UIViewController is a UITableView and a UITabBarItem. I believe I'll also have to handle taps on the status bar.
I am unsure as how I should register for touches on them (so that I can force any of the text fields to call resignFirstResponder.
I thought I might have to handle UIResponder's
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
for the table view and tab bar item but neither of them are UIControls so I can't use
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
UIWindow is also a UIResponder but again, I can't seem to get touch events for it.
Any help would be much appreciated,
CS
If you had one text field I'd add touches began into the UIViewController it belongs to and do it like this...
- (void)touchesBegan ... cant remember full name
{
if ([touches count] > 1) {
return;
}
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView self.view];
if (!CGRectContainsPoint(self.textField.frame, touchPoint)) {
//touch originated outside textField.
[textField resignFirstResponder];
}
}
If you have more than one text field then just do the CGRectContainsPoint check for each of them inside the if.
When you have a static UITableView it "eats" the touch events. So what I did was by subclassing UITableView and then added a delegate which reports touch events.

Touch Event on UIView

Does anyone have any sample code for detecting touches on a dynamically created UIView? I have found some references to touchesBegan but cannot figure out how to implement it...
A very general way to get touches is to override these methods in a custom UIView subclass:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
The official docs for these methods is under Responding to Touch Events in the UIResponder class docs (UIView inherits those methods since it's a subclass of UIResponder). Longer and more introductory docs can be found in the Event Handling Guide for iOS.
If you just want to detect a tap (touch-down, then touch-up within your view), it's easiest to add a UIButton as a subview of your view, and add your own custom method as a target/action pair for that button. Custom buttons are invisible by default, so it wouldn't affect the look of your view.
If you're looking for more advanced interactions, it's also good to know about the UIGestureRecognizer class.
Create touch event with UIAnimation on UIView , you can manage touches on UIView anywhere .
Following Code : here self.finalScore is a UIView , and cup is a UIImageView . I handle
the touch event on UIImageView , it present inside the UIView .
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch1 = [touches anyObject];
CGPoint touchLocation = [touch1 locationInView:self.finalScore];
CGRect startRect = [[[cup layer] presentationLayer] frame];
CGRectContainsPoint(startRect, touchLocation);
[UIView animateWithDuration:0.7
delay:0.0
options:UIViewAnimationCurveEaseOut
animations:^{cup.transform = CGAffineTransformMakeScale(1.25, 0.75);}
completion:^(BOOL finished) {
[UIView animateWithDuration:2.0
delay:2.0
options:0
animations:^{cup.alpha = 0.0;}
completion:^(BOOL finished) {
[cup removeFromSuperview];
cup = nil;}];
}];
}
Like UITapGestureRecognizer is another way of handle the touch events on UIView ....
UITapGestureRecognizer *touchOnView = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(releaseButAction)] autorelease];
// Set required taps and number of touches
[touchOnView setNumberOfTapsRequired:1];
[touchOnView setNumberOfTouchesRequired:1];
// Add the gesture to the view
[[self view] addGestureRecognizer:touchOnView];
Create your own custom UIView from a subclass you created by inheriting UIView and override the following method inside the sub-class,
(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
}
With gesture recognizer, it is much easy to catch touch events.
Find one guested from component library in storyboard:
For example, drag Tap Gesture Recognizer to your view. It is not shown in the view UI. You can find it from Document outline in the left panel in Storyboard:
The final step is to link it (by control-drag) to the view as delegate where touch is monitored, and control-drag to your view controller class as an action. Here is the picture of link connections.
and action code:
#IBAction func tapAction(_ sender: Any) {
// touch is captured here.
}
Instead of capturing touch using gesture, I would suggest to change UIView parent class to UIControl, so that it can handle touchUpInside event
From:
#interface MyView : UIView
To:
#interface MyView : UIControl
and then add this line for view-
[self addTarget:self action:#selector(viewTapped:) forControlEvents:UIControlEventTouchUpInside];
Because gesture may create problem while scrolling.
My method is simply change the UIView to UIControl class in InterfaceBuilder IdentityInspector, then the ConnectionsInspector will instantly have the touch event ready for hook.
zero code changes.

Resources