I have two custom uibuttons.
#interface myButton : UIButton
I overwrite several methods like
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// do something
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
[self.nextResponder touchesMoved:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
if (!CGRectContainsPoint(self.bounds, touchPoint)) {
[self touchesCancelled:touches withEvent:event];
}
return;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// do something
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
return;
}
The thing I want is , when I touch a button, I can keep moving my touch to another button. I tired to call touchesCancelled when the touch is out of the bound of the first button I touched. So I "think" then I move to another button it will be a new touch event. But it doesn't work like this.
Did I do something wrong? Or the touchesCancelled method is not used for like this?
Thanks in advance!
Your suspesions are correct, this is not how touchesCancelled:withEvent: was intended to be used. From the documentation:
This method is invoked when the Cocoa Touch framework receives a system interruption requiring cancellation of the touch event; for this, it generates a UITouch object with a phase of UITouchPhaseCancel. The interruption is something that might cause the application to be no longer active or the view to be removed from the window.
Your responder will receive the touches cancelled event if your user receives an incoming phone call, SMS or their alarm goes off etc. It should be used to clean up any state information that was established in the other touch events.
It seems as though you want to change the responder associated with the touch events mid-touch i.e. when you drag the touch from the bounds of the first button and enter that of the second button it should become the responder recieving the touch events. Unfortunately that is not the way responders are designed to work. Once a UIView is identified as being the responder, as returned in hitTest:withEvent:, this will be the UIView to receive touch events.
A possible workout to achieve what you want would be to handle the touch events (touchesBegan:withEvent:, touchesMoved:withEvent: etc.) in a superview that contains both of your buttons. Then your superview will receive the touch events and you can take action depending on which button's frame you are within:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
CGPoint touchLocation = [touch locationInView:self.view];
UIButton *button;
if (CGRectContainsPoint(self.button1.frame, touchLocation))
{
button = self.button1;
NSLog(#"touchesMoved: First Button");
}
else if (CGRectContainsPoint(self.button2.frame, touchLocation))
{
button = self.button2;
NSLog(#"touchesMoved: Second Button");
}
// Do something with button...
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
CGPoint touchLocation = [touch locationInView:self.view];
UIButton *button;
if (CGRectContainsPoint(self.button1.frame, touchLocation))
{
button = self.button1;
NSLog(#"touchesMoved: First Button");
}
else if (CGRectContainsPoint(self.button2.frame, touchLocation))
{
button = self.button2;
NSLog(#"touchesMoved: Second Button");
}
// Do something with button...
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
CGPoint touchLocation = [touch locationInView:self.view];
UIButton *button;
if (CGRectContainsPoint(self.button1.frame, touchLocation))
{
button = self.button1;
NSLog(#"touchesEnded: First Button");
}
else if (CGRectContainsPoint(self.button2.frame, touchLocation))
{
button = self.button2;
NSLog(#"touchesEnded: Second Button");
}
// Do something with button...
}
}
Related
In my app I have an UIView on top of UISplitViewController (used "addSubView"). What I wanna do is to let the UIView handle the touch and then redirect it to the parent view so it could also handle it.
I think i have a work around for what you try to do. You'll have to subclass your topView and implement the following two methods:
The first method will handle your touch for the buttomView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
CGPoint bottomViewHit = [bottomView convertPoint:point fromView:self];
if ([topView pointInside:topViewHit withEvent:event]) {
//manage your bottomView touch here..
return bottomView;
}
return [super hitTest:point withEvent:event];
}
The second method will handle the topView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:touch.view];
// manage your touch for topView here...
[view touchesBegan:touches withEvent:event];
}
I have been looking at how to invoke different touch methods depending on where the user touches on the screen. I presume this should be fairly simple in Sprite Kit but I can't find anything on it. Currently I am using the following to make the character jump.
How would I only use this method if it is touched on the left or the right of the screen? So a right touch calls one method and a left touch calls another. Thanks.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
if (isJumping == NO){
isJumping = YES;
SKSpriteNode* charNode = (SKSpriteNode*)[self childNodeWithName:#"character"];
[charNode runAction:jumpAnimation];
[charNode runAction:jumpMovement];
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
if(touchLocation.x < self.size.width/2)
NSLog(#"left side");
if(touchLocation.x > self.size.width/2)
NSLog(#"right side");
}
I created a very simple app that contains a draggable UIImageView but I faced a problem that the image can be dragged without touching it. I'm sure that the hole issue is from anyObject but I have no idea how to replace it I tried self.view.image but it failed. So here's my code
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
lineView.center = location;
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchesBegan:touches withEvent:event];
}
any ideas?
Consider using a pan gesture recogniser. Add it only to the image view (and enable user interaction on the view). Now you will only get action method callbacks from the gesture when the view has actually been touched, your code becomes simpler, and you can move the view with that position.
Also, in your current code, it's weird to call touchesBegan: from touchesMoved:. If you keep that code (because you don't want to use a gesture), you should refactor the code that moves the view out into a different method and have both touchesBegan: and touchesMoved: call that method.
Try the following
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
if ([lineView pointInside:location withEvent:event])
lineView.center = location;
}
The code below is based on the idea of how to make a UIImageView be able to be dragged around the ViewController. When I use this code however, I click on a different location instead of pressing on the Image and it teleports to that location instead of requiring me to always drag the image. I want the code below to only work when pressing on that specific image. Please Help-
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
image.center = location;
[self ifCollided];
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchesBegan:touches withEvent:event];
}
It's teleporting simply because you don't have any check for whether the user has in fact touched the image, so any touch causes the image to jump to that location. What you need to do is check if the user has touched the image, then move it only if they have. Try the following code in the ViewController, assuming 'image' is the draggable view:
You'll need to create a variable/property on your ViewController to track if the view is being dragged. If you need just one image, you can use a BOOL (the code below assumes you've done this, called isDragging).
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:image];
if([image pointInside:location withEvent:event]) {
isDragging = YES;
}
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
if(isDragging)
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self.view];
image.center = location;
[self ifCollided];
}
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
isDragging = NO;
}
This code basically does a check in touchesBegan and sets the property to true if you touch inside the image, moves it in touchesMoved if your initial touch was on the image, and finally unsets the check in touchesEnded.
So I have a Subclass of UIView that is suppose to detect touches. The view detect touches only if the touches started inside the current view. When the touches start outside of the view and they move inside my custom view touchesMoved doesn't get called. Any solution to detect moving touches that have not started in the current view?
#implementation MycustomView
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// This only gets called if touches have started in the current View
}
#end
The following solution worked. I have multiple instances of MyCustomView; as the touches move I want to detect the views that are being touched
I ended up moving touch detection from MyCustomView to its superView, so the following code is no longer in MyCustomView class:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.contentView];
for (UIView *view in self.contentView.subviews)
{
if ([view isKindOfClass:[MyCustomView class]] &&
CGRectContainsPoint(view.frame, touchLocation))
{
}
}
}
this should fix it:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
for (UIView* subView in self.subviews)
{
if([subView pointInside:[self convertPoint:touch toView:subView] withEvent:event])
{
//do your code here
}
}
}
One way to do it (though there might be others) is to disable user interaction for the subviews and make their parent view track the movement (use the hitTest method to figure out which view the touch is currently over).
Try this....
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch *touch in touches)
{
CGPoint touchPointFirstBtn = [touch locationInView:self.ChordView];
if(CGRectContainsPoint(_btnC.frame, touchPointFirstBtn))
{
if (!_btnC.isHighlighted)
{
if(!Boolean)
{
title = #"C";
[_tlbView reloadData];
NSLog(#"%#",#"touches C");
}
[_btnC setHighlighted:YES];
Boolean = YES;
}
}
else
{
[_btnC setHighlighted:NO];
Boolean = NO;
}
}