I have an NSArray whit 15 UIImageViews:
#interface ViewController : UIViewController{
NSArray *ArrayImages1;
NSArray *ArrayImages2;
}
in viewDidLoad:
ArrayImages1 = [[NSArray alloc] initWithObjects: a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, nil];
Where a1, a2... are the outlets of the UIImageViews
And the same for ArrayImages2
TouchesBegan and TouchesMoved:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self.view];
UIImageView *posible;
int imagen;
if (point.x < 161) {
imagen = Contador1;
if (Contador1 > 14) {imagen = Contador1 - 15;}
imagen--;
posible = [ArrayImages1 objectAtIndex:imagen];
}
else if (point.x > 159) {
imagen = Contador2;
if (Contador2 > 14) {imagen = Contador2 - 15;}
imagen--;
posible = [ArrayImages2 objectAtIndex:imagen];
}
if ([touch view] != posible) { return; }
original2 = posible.center;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self.view];
UIImageView *posible;
int imagen;
if (point.x < 161) {
imagen = Contador1;
if (Contador1 > 14) {imagen = Contador1 - 15;}
imagen--;
posible = [ArrayImages1 objectAtIndex:imagen];
}
else if (point.x > 159) {
imagen = Contador2;
if (Contador2 > 14) {imagen = Contador2 - 15;}
imagen--;
posible = [ArrayImages2 objectAtIndex:imagen];
}
if ([touch view] != posible) { return; }
posible.center = point;
}
I have to know if the touch was in one of the two posible UIImageViews, and if it was, move it.
The Contador1 and Contador2 ints, are counters that counts how many UIImageView are visible, the user only can move the last 2 of them.
It works, the thing is when i touch outside, it makes the app crash.
If i change in touchesBegan and TouchesMoved, the index of "posible = [ArrayImage..", for 0, it only works for the first UIImageView (i understand why), but it doesent crash.
Any ideas?
I have to know if the touch was in one of the two possible UIImageViews
I can't follow your code very well but it seems like you could simplify things if you first check if the point is within the rect of a view. Then base your logic off of the result. Something like
Using CGRectContainsPoint:
bool CGRectContainsPoint (
CGRect rect,
CGPoint point
);
UIImageView *foundView
for(UIImageView* theView in ArrayImages1){
if (CGRectContainsPoint(theView.frame, touchPoint){
foundView = theView;
break;
}
}
Then...
if (foundView != nil){
// do some logical thing
}
Or...
if ([foundView isEqual:someOtherView]){
// I may have the syntax wrong on the above
}
Related
Am working on kind of seating arrangement application. Where the app allows the admin to arrange the seatings by click and move the each seat and then save the seating arrangement with frame sizes of each seat. I tried by loading 5 UIImageView on custom view and move the imageview but, only one imageview is getting moved. Rest of the imageviews not getting moved. Can you please help me on this?
- (void) addSeatsToTheView {
for (int i=0; i<5; i++) {
self.hotelImage = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 50, 50)];
self.hotelImage.image = [UIImage imageNamed:#"DiningIcon"];
self.hotelImage.userInteractionEnabled = YES;
[self.hotelImage setUserInteractionEnabled:YES];
self.hotelImage.tag = i;
[self.hotelView addSubview:self.hotelImage];
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if (touch.view == self.hotelImage) {
CGPoint location = [touch locationInView:self.hotelView];
NSLog(#"Begen Touch Location: %#", NSStringFromCGPoint(location));
self.hotelImage.frame=CGRectMake(location.x, location.y, 50, 50);
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if (touch.view == self.hotelImage) {
CGPoint location = [touch locationInView:self.hotelView];
NSLog(#"Begen Touch Location: %#", NSStringFromCGPoint(location));
self.hotelImage.frame=CGRectMake(location.x, location.y, 50, 50);
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if (touch.view == self.hotelImage) {
CGPoint location = [touch locationInView:self.hotelView];
NSLog(#"Begen Touch Location: %#", NSStringFromCGPoint(location));
self.hotelImage.frame=CGRectMake(location.x, location.y, 50, 50);
}
}
Once the admin arranged the seatings we have to save all the visible uiimageview framesizes. Thanks.
Edited:
I tried the using UIPanGestureRecognizer but, only one imageview getting moved. Don't know where am doing wrong? Can you please help me? Thanks.
- (void) addSeatsToTheView {
for (int i=0; i<5; i++) {
self.hotelImage = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 50, 50)];
self.hotelImage.image = [UIImage imageNamed:#"DiningIcon"];
self.hotelImage.userInteractionEnabled = YES;
[self.hotelImage setUserInteractionEnabled:YES];
self.hotelImage.tag = i;
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(gestureRecognizerMethod:)];
[self.hotelImage addGestureRecognizer:panGestureRecognizer];
[self.hotelView addSubview:self.hotelImage];
}
}
- (void)gestureRecognizerMethod:(UIPanGestureRecognizer *)recogniser
{
if (recogniser.state == UIGestureRecognizerStateBegan || recogniser.state == UIGestureRecognizerStateChanged)
{
CGPoint touchLocation = [recogniser locationInView:self.hotelView];
self.hotelImage.frame = CGRectMake(touchLocation.x, touchLocation.y, 50, 50);
}
}
Don't use touches methods for this; you'll go insane. Make each image view user-interactive and give it a UIPanGestureRecognizer. There is standard code for the pan gesture recognizer's action handler for following a finger, i.e. making the view draggable.
Once you've done that, everything stems from your misuse of self.hotelImage. Get rid of it entirely. In your for loop, just use a local variable, UIImageView* hotelImage = .... In the gesture recognizer method, use [recogniser view] to refer to the image view to which this gesture recognizer is attached. Everything will sort itself out after that!
I have a character in my game that I can move left/right and jump. I am using touchesBegan to do that. But when I move left ( keep touching the screen -> makes character faster and faster ), it only jumps when i release it. I would like to jump and move left at the same time.
Here is some of my code :
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self.view];
if((point.x < moveLeftButton.frame.size.width))
{
if((point.y > JumpButton.frame.size.height))
{
leftSide = YES;
sanchez.image = [UIImage imageNamed:#"characterL2"];
}
}
if((point.x) > (backGround.frame.size.width - moveRightButton.frame.size.width))
{
if((point.y > JumpButton.frame.size.height))
{
rightSide = YES;
sanchez.image = [UIImage imageNamed:#"characterR2"];
}
}
if( notJumping && (point.y < JumpButton.frame.size.height) && (sanchezStopAll == NO))
{
AudioServicesPlaySystemSound(jump);
sanchezJumping = 5.5;
notJumping = NO;
}
[self animation];
}
I am not using buttonPressed because they are hidden and I think you can't click hidden buttons.
This is how it looks like if its not hidden:
Thanks for any Help.
You'll only get a single touch by default unless you set multipleTouchEnabled = YES. Then your code should work as expected.
For example:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.multipleTouchEnabled = YES;
}
I understand how to make a draggable image, but I am having trouble making an image from a class file be draggable from my main ViewController.m file. My class is called "bomb". Every two seconds, a new bomb is created, and with it a bombImage (an object of bomb). The bomb is added to an NSMutableArray (bombArray).
- (void) newBomb
{
bomb *bomb1 = [[bomb alloc] init];
[bombArray addObject: bomb1];
[bomb1 displayBombOnView:self.view]; //displayBombOnView just makes a new bomb in a random location
}
I am trying to make it so that the user can drag each "bomb" around.
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event : (bomb *) bomb
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
bomb->bombImage.center = location;
}
-(void) touchesMoved:(NSSet*)touches withEvent:(UIEvent *)event
{
bomb *tempBomb = [[bomb alloc] init];
arrayCount = [bombArray count];
for (int k = 0; k<arrayCount; k++)
{
tempBomb = [bombArray objectAtIndex:k];
CGPoint tappedPt = [[touches anyObject] locationInView: self];
int xPos = tappedPt.x;
int yPos = tappedPt.y;
if ((xPos >= tempBomb->bombImage.center.x - 25 && xPos <= tempBomb->bombImage.center.x + 25) && (yPos >= tempBomb->bombImage.center.y - 25 && xPos <= tempBomb->bombImage.center.y + 25))
{
[self touchesBegan:touches withEvent:event : [bombArray objectAtIndex:k]];
break;
}
}
}
It builds, but then when I try to drag the image, it crashes, saying Thread 1: signal SIGABRT. Any help would be greatly appreciated.
Instead of what you're doing, use a UIPanGestureRecognizer. Add a recognizer to each bomb image view when you create it and then when the gesture recognizer calls your action method you can directly access the view and use the recognizer position to move the view.
I want to detect a two-finger diagonal swipe that starts from the bottom right of the screen to the middle. I tried adding UISwipeGestureRecognizer with direction set as "UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionLeft" but to no vail as the handler is getting invoked even if I start the swipe from the middle of the screen to the top left.
Do I need to sub-class UIGestureRecognizer or can I handle this using touchesBegan and touchesMoved ?
You need to subclass it to use touchesBegan and touchesMoved anyway. I'd do UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionLeft like you said, then set up two CGRects, one for acceptable starting points, one for acceptable end points. Then use the UIGestureRecognizerDelegate method gestureRecognizer:shouldReceiveTouch:, and check if the touch point is in the acceptable start rect by using CGRectContainsPoint(). Then (I think) in your UISwipeGestureRecognizer subclass, override touchesEnded:withEvent:, and check if the end touch is in the acceptable rect. If it's not, set the state to UIGestureRecognizerStateCancelled (or however you're supposed to cancel a gesture). Also make sure the view it's attached to has its multipleTouchEnabled property set. I haven't actually tried this, but something of the sort should do it. Good luck!
EDIT
Actually, if you didn't want to have to worry about specific rect values for the acceptable start/end points, and make it device independent, you could do this:
//swap in whatever percentage of the screen's width/height you want in place of ".75f"
//set the origin for acceptable start points
CGFloat startRect_x = self.view.frame.size.width * .75f;
CGFloat startRect_y = self.view.frame.size.height * .75f;
//set the size
CGFloat rectWidth = self.view.frame.size.width - startRect_x;
CGFloat rectHeight = self.view.frame.size.height - startRect_y;
//make the acceptable start point rect
CGRect startRect = CGRectMake(startRect_x, startRect_y, rectWidth, rectHeight);
//set the origin for the accepable end points
CGFloat endRect_x = self.view.center.x - rectWidth/2;
CGFloat endRect_y = self.view.center.y - rectHeight/2;
//make the acceptable end point rect
CGRect endRect = CGRectMake(endRect_x, endRect_y, rectWidth, rectHeight);
the touches method of cause can do every Gesture, the Gesture is supported since ios3.2.
i can give you a simple code , you maybe modify by yourself.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
isTwoFingersBegin = NO;
isTwoFingersEnd = NO;
UITouch *touch = [touches anyObject];
UIView *touchView = [touch view];
if ([touches count] == 2)
{
isTwoFingersBegin = YES;
}
touchStartPoint = [touch locationInView:self.view];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
isSwip = YES;
}
#define TOUCH_MOVE_EFFECT_DIST 30
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
UIView *touchView = [touch view];
touchEndPoint = [touch locationInView:self.view];
if ([touches count] == 2)
{
isTwoFingersEnd = YES;
}
CGPoint deltaVector = CGPointMake(touchEndPoint.x - touchStartPoint.x, touchEndPoint.y - touchStartPoint.y);
if (fabsf(deltaVector.x) > TOUCH_MOVE_EFFECT_DIST
&&fabsf(deltaVector.y) > TOUCH_MOVE_EFFECT_DIST
&& isSwip &&isTwoFingersBegin&&isTwoFingersEnd) {
theSwipGesture=RightUpGesture;
}
else if (fabsf(deltaVector.x) <- TOUCH_MOVE_EFFECT_DIST
&& fabsf(deltaVector.y) <- TOUCH_MOVE_EFFECT_DIST
&& isSwip&&isTwoFingersBegin&&isTwoFingersEnd) {
theSwipGesture=LeftDownGesture;
}
isSwip = NO;
}
You can use a UIPanGestureRecognizer
- (void)viewPanned:(UIPanGestureRecognizer *)panGR
{
CGPoint translation = [panGR translationInView:self];
CGFloat threshold = self.bounds.size.width/2;
// Detect
Direction direction = DirectionUnknown;
if (translation.x > threshold) {
if (translation.y > threshold) {
direction = DirectionBottomRight;
} else if (translation.y < -threshold) {
direction = DirectionTopRight;
} else {
direction = DirectionRight;
}
} else if (translation.x < -threshold) {
if (translation.y > threshold) {
direction = DirectionBottomLeft;
} else if (translation.y < -threshold) {
direction = DirectionTopLeft;
} else {
direction = DirectionLeft;
}
} else {
if (translation.y > threshold) {
direction = DirectionBottom;
} else if (translation.y < -threshold) {
direction = DirectionTop;
}
}
}
One possible solution would be to map off a group of coordinates on the iPhone's screen where the swipe could potentially start, and another where it could potentially end. Then in the touchesBegan: and touchesMoved: methods, you could compare the starting and ending points of the swipe and determine whether it qualified as diagonal.
Thanks Guys!
I ended up writing custom code in touchesBegan, touchesMoved and touchesEnded and ot works like charm.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([touches count] == 2) {
CGPoint nowPoint = [[touches anyObject] locationInView:self];
if( nowPoint.x >= ALLOWED_X)
swipeUp = YES;
}
[super touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
if ([touches count] == 2 && swipeUp) {
CGPoint nowPoint = [[touches anyObject] locationInView:self];
CGPoint prevPoint = [[touches anyObject] previousLocationInView:self];
if( nowPoint.x <= prevPoint.x && nowPoint.y <= prevPoint.y){
}
else {
swipeUp = NO;
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
CGPoint nowPoint = [[touches anyObject] locationInView:self];
if ([touches count] == 2 && swipeUp && nowPoint.x <= DELTA_X && nowPoint.y <= DELTA_Y) {
NSLog(#"Invoke Method");
}
swipeUp = NO;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
swipeUp = NO;
}
i really got stuck in a week about this case.
i have a UIBarButtonItem inside UINavigationItem, the hierarchy is like this
The BarButtonItem is a wrapper of segmentedControl. The UIBarbuttonitem and UIsegmentedControl are made programmatically, but the others are made in IB.
in this case, i want to show a view after pressing or touching the barbuttonitem. In several thread i read in this forum, i knew that UIBarbuttonItem didn't inherit UIResponder, so i choose the NavigationBar to get the touch, and i define a frame for it.
this is the code i made :
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
navBar = self.navigationController.navigationBar;
int index = _docSegmentedControl.selectedSegmentIndex;
NSLog(#"index di touches began : %d", index);
CGFloat x;
if (index == 0) {
x = 0.0;
}else if (index == 1) {
x = widthSegment + 1;
}else if (index == 2) {
x = 2*widthSegment + 1;
}else if (index == 3) {
x = 3*widthSegment+ 1;
}else if (in dex == 4) {
x = 4*widthSegment + 1;
}
CGRect frame = CGRectMake(x, 0.00, widthSegment, 46.00);
UITouch *touch = [touches anyObject];
CGPoint gestureStartPoint = [touch locationInView:navBar];
NSLog(#"gesturestart : %f, %f", gestureStartPoint.x, gestureStartPoint.y);
if (CGRectContainsPoint(frame, gestureStartPoint)) {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(segmentItemTapped:) object:[self navBar]];
NSLog(#"cancel popover");
}
}
the navBar was declare in myViewController.h and i set it as an IBOutlet.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
int index = _docSegmentedControl.selectedSegmentIndex;
NSLog(#"index di touches ended : %d", index);
navBar = self.navigationController.navigationBar;
CGFloat x;
if (index == 0) {
x = 0.0;
}else if (index == 1) {
x = widthSegment + 1;
}else if (in dex == 2) {
x = 2*widthSegment + 1;
}else if (index == 3) {
x = 3*widthSegment+ 1;
}else if (index == 4) {
x = 4*widthSegment + 1;
}
CGRect frame = CGRectMake(x, 0.00, widthSegment, 46.00);
UITouch *touch = [touches anyObject];
CGPoint gestureLastPoint = [touch locationInView:navBar];
NSLog(#"lastPOint : %d", gestureLastPoint);
if (CGRectContainsPoint(frame, gestureLastPoint)) {
if (touch.tapCount <= 2) {
[self performSelector:#selector(segmentItemTapped:) withObject:nil afterDelay:0.0];
}
}
}
touchesBegan and touchesEnded was detected when i tap at the toolbar, NOT in the navbar.
i did implemented the hitTest method like this :
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *touchedView = [super hitTest:point withEvent:event];
NSSet* touches = [event allTouches];
// handle touches if you need
return touchedView;
}
but it still nothing get better.
Somebody can decribe why this is happen?
Regards
-Risma-
you can simply add an action to the barbutton item like
[self.mybarbutton setAction:#selector(barButtonTapped:)];
[self.mybarbutton setTarget:self];