Dragging UIImages to the selected area - objective-c

Newbie obj-c question.
My task is to make visually represented test for iPad. In view I have three UIImages (with images of answers to test question) what will dragged to area for answer. If selected right image, then it needs to stay in this area, if not - it goes back into the start position. If user stop dragging not in area for answer it also needs to goes back to the start position.
I tried to implement this: http://www.cocoacontrols.com/platforms/ios/controls/tkdragview but it's too hard for me because I am a super newbie.
I implemented simple dragging of images by PanRecognizer, so every from three images dragging
-(IBAction)controlPan:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
If I think in right way, I need to set CGPoint's with start and destination coordinates and then to customize Pan Gestures method? If it's not right, in what way can I do this?

You can consider this three method, maybe these are easier for you:
– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
Detailed demo for – touchesBegan:withEvent: is:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
UITouch *touched = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touched.view];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
UITouch *touched = [[event allTouches] anyObject];
// Here I suppose self.imageView contains the image user is dragging.
CGPoint location = [touch locationInView:touched.view];
// Here the check condition is the image user dragging is absolutely in the answer area.
if (CGRectContainsRect(self.answerArea.frame, self.imageView.frame)) {
// set transition to another UIViewController
} else {
self.imageView.center = location; // Here I suppose you just move the image with user's finger.
}
}
Here is the Apple's doc for this UIResponder Class Reference

Related

UISlider change values by touching its track

I am beginner in ios and I have done basic functionality with UISlider , changing its value on dragging thumb. But now in my app I want to move the thumb of slider gradually in same direction where I am touching slider's track without dragging the thumb of slider. Thumb must reach to exact touched position on the track in 2 or more steps.
I know it requires involvement of UITouch but unable to understand HOW?
You need to subclass UISlider to add this functionality. After subclassing, you need to implement touchesBegan and touchedMoved in your subclass. Well, here how i did
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGFloat maxX = CGRectGetMaxX(self.frame);
CGFloat minX = CGRectGetMinX(self.frame);
int value = (maxX - minX) /(self.maximumValue - self.minimumValue);
[self setValue:([touch locationInView:self].x - minX) / value animated:YES];
[self beginTrackingWithTouch:touch withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[self continueTrackingWithTouch:[touches anyObject] withEvent:event];
}
You need more work to stabilise a little bit more when user first tap, but i hope you get the idea.

Dragging multiple images in iOS

I'm brand new to touch and drag, and I'm trying to make eight draggable images. Here's what it looks like in my ViewController.m file:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self.view];
//check for which peg is touched
if ([touch view] == darkGreyPeg){darkGreyPeg.center = location;}
else if ([touch view] == brownPeg){brownPeg.center = location;}
//there are six more else ifs
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[self touchesBegan:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[self ifCollided];
}
If I take out the if statements, and the locationInView:self.view to locationInView:touch.view, I'm able to drag the darkGreyPeg around with no problems, and it triggers my [ifCollided] whenever appropriate.
I'm watching a youTube tutorial (Milmers Xcode tutorials, "Dragging Multiple Images"), and he has exactly this same type of code, and mine doesn't work. Can anyone point me in the direction of why?
Thanks.
Try to check the User interaction Enabled & multiple touch in your view images atribute. Without check the user interaction enabled you can't use multiple dragging. I have try this, and succes to drag multiple image, label or button.
You should not implement these methods in your ViewController, but in your View class that you want to be able to drag around instead.
I think the problem is using == to compare objects:
[touch view] == darkGreyPeg
You should use isEqual: to compare objects:
[[touch view] isEqual:darkGrayPeg]
After Edit: I think the problem is that you forgot to set userInteractionEnabled to YES for the image views. Without doing that, the touch.view will be the superview, not the image view. Also, you probably don't need all those if statements to determine which image view to move, you can just use touch.view:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self.view];
if (![touch.view isEqual:self.view]) touch.view.center = location;
}
If you have other views, besides self.view that you don't want to move, then you either have to exclude them too, or use a different exclusion condition (like only move the object if it's an image view, or only an object with a certain tag value).

UIView not passing touches to subviews

I'm sure this is a basic misunderstanding of the responder chain - has it changed since iOS4? I have a view with some subviews. The superview has no purpose other than positioning the subviews, and should have nothing to do with handling touches. I want the subviews to listen for touches, but the superview seems to block touch events. I thought superviews passed touches on to subviews? I've read several posts on this, but I can't get my head around it. Several posts seem to suggest that setting userInteractionEnabled to NO for the superview will work, but doing this still doesn't seem to let the touch through.
In case it's not clear what I mean, here's some simplified code. Tapping inside the red view does NOT trigger the NSLog...
#implementation ViewController
#synthesize redView;
- (void)viewDidLoad
{
UIView *blueView = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 200, 400)];
blueView.backgroundColor = [UIColor blueColor];
[self.view addSubview:blueView];
redView = [[UIView alloc]initWithFrame:CGRectMake(20, 20, 40, 40)];
redView.backgroundColor = [UIColor redColor];
[blueView addSubview:redView];
[super viewDidLoad];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
if (CGRectContainsPoint(redView.frame, touchPoint)) {
NSLog(#"red got touched");
}
}
#end
The coordinates of the touch you are receiving are expressed in the coordinate system of the enclosing view. So you need to correct them with the offset of the blueView. One way would be to add a blueView property to your object and then correct in the touchesBegan method:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
touchPoint.x -= blueView.frame.origin.x;
touchPoint.y -= blueView.frame.origin.y;
if (CGRectContainsPoint(redViewFrame, touchPoint)) {
NSLog(#"red got touched");
}
}
Or you could subclass UIView for the blueView and override touchesBegan there
I can see an error here isreally important to call [super viewDidLoad] right after the begin bracket of that method. Second i can suggest you to use a gesture recognizer, that are based on the target action pattern and the are a lot simply to use. Third you are messing with coordinate system.

How can I convert the coordinates of a touch event on a subview to the coordinates in its parent view?

I'm diving into iOS development and I'm playing with touch events. I have a class named UIPuzzlePiece that's a subclass of UIImageView and it represents the puzzle piece objects that you can move around on the screen. My goal is to be able to move the puzzle pieces around on the screen with my finger.
Currently, I have the touchesBegan and touchesMoved events implemented inside the UIPuzzlePiece class...
// Handles the start of a touch
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event touchesForView:self] anyObject];
CGPoint cgLocation = [touch locationInView:self];
[self setCenter:cgLocation];
}
// Handles the continuation of a touch.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event touchesForView:self] anyObject];
CGPoint cgLocation = [touch locationInView:self];
[self setCenter:cgLocation];
}
The problem I'm facing is the CGPoint location that is returned represents the location inside the UIPuzzlePiece view, which makes sense, but I need to know the location of the touch inside the parent view. That way the statement [self setCenter:cgLocation] will actually move the UIPuzzlePiece to the location of the touch. I can always write some hacky algorithm to convert it, but I was hoping there's a better or simpler way to accomplish my goal. If I only had a single puzzle piece, I would just implement the touch event code inside the view controller of the parent view, but I have many many puzzle pieces, which is why I'm handling it inside the UIPuzzlePiece view.
Your thoughts?
Thanks so much in advance for your wisdom!
UIView implements -convertRect:fromView:, -convertRect:toView:, -convertPoint:fromView: and -convertPoint:toView:. Sounds like you just need to use one of the latter methods to convert between view coordinate spaces. For example, if you want to convert a CGPoint from the coordinate space of self to the parent view, you can use either [self convertPoint:thePoint toView:self.superview] or you can use [self.superview convertPoint:thePoint fromView:self] (they will do the same thing).

touches in touch event handling in UIView vs UIViewControllers

So, I'm capturing multiple touches and determining the number and where each of the touches occurred and I'm seeing different behavior between a UIView UIViewController.
Basically, the event handler is coded below: (in this case the touchesEnded, but it really doesn't matter). What happens in the View, is that I get the entire collection of touches, but in the controller, I get only one touch at a time, that is there is never a collection of touches, but the TouchesEnded gets executed for each touch that occurred in the same moment.
I add the subviews as identically as possible...
Can someone 'spain to me what's going on? Why doesn't the controller version give me the collection?
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
int total = 0;
for (UITouch *touch in touches)
{
for(UIView *myView in [contentView subviews])
{
if (CGRectContainsPoint([myView frame], [touch locationInView:self.view]))
total++; // this is always 1 for the UIViewController
// but I get the full number within the UIView version
}
}
}
I suspect you are getting the touches but that the views are different. Check that contentView is the same and has the same subviews.
I am not sure that I am right but this thing always work for me.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
If(touch.view==your view)
{
NSLog("do your task here");
}
}