drag & rotate gesture on iPad - iphone

I have a problem, I want to add some gesture to a uibutton for move and rotate it, I use this code
[self.button addTarget:self action:#selector(wasDragged:withEvent:) forControlEvents:UIControlEventTouchDragInside];
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(handleRotate:)];
[self.button addGestureRecognizer:rotationGesture];
- (void)wasDragged:(UIButton *)button withEvent:(UIEvent *)event
{
// get the touch
UITouch *touch = [[event touchesForView:self.button] anyObject];
// get delta
CGPoint previousLocation = [touch previousLocationInView:self.button];
CGPoint location = [touch locationInView:self.button];
CGFloat delta_x = location.x - previousLocation.x;
CGFloat delta_y = location.y - previousLocation.y;
// move button
self.button.center = CGPointMake(self.button.center.x + delta_x,self.button.center.y + delta_y);
}
- (void)handleRotate:(UIRotationGestureRecognizer *)recognizer {
if(recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateChanged)
{
recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation);
[recognizer setRotation:0];
}
}
all work I can rotate the button and move the button, the problem is if I rotate the button and then move it...in this case not work, I can move the button but not where I want...where is the problem?

You are calculating the difference between the position of touches relative to the button. This does not work as expected when the button is rotated. Instead you should try computing it relative to the superview of the button or the window.
Instead of this:
CGPoint previousLocation = [touch previousLocationInView:self.button];
CGPoint location = [touch locationInView:self.button];
You should use this:
CGPoint previousLocation = [touch previousLocationInView:self.button.superview];
CGPoint location = [touch locationInView:self.button.superview];

Related

UITouch, Drag and Drop not working at all

I have a UIView and on the top of him I've got UIButton, UITableView and UINavigationBar. what I want to do is, when you click on the UIButton and drag it, all the view will move to the left side only, until the screen ends. I mean that you can drag the view to the left and when you stop touching, the view will stop where your finger stopped touching the screen.
I can't do it, he shows me only the "Touches Began 1" and thats it. what seems to be my problem here?
Thanks alot everyone!
float oldX, oldY;
BOOL dragging;
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
NSLog("Touches Began 1");
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (CGRectContainsPoint(btnOpen.frame, touchLocation))
{
NSLog("Touches Began 2");
dragging = YES;
oldX = touchLocation.x;
oldY = touchLocation.y;
}
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (dragging)
{
NSLog("Dragging!");
CGRect frame = mainView.frame;
frame.origin.x = mainView.frame.origin.x + touchLocation.x - oldX;
frame.origin.y = mainView.frame.origin.y + touchLocation.y - oldY;
mainView.frame = frame;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog("Touches Ended!");
dragging = NO;
}
- (void)viewDidLoad
{
[btnOpen addTarget:self action:#selector(touchesBegan:withEvent:) forControlEvents: UIControlEventTouchDown];
[btnOpen addTarget:self action:#selector(touchesMoved:withEvent:) forControlEvents: UIControlEventTouchDragInside];
[btnOpen addTarget:self action:#selector(touchesEnded:withEvent:) forControlEvents: UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
}
You are asking for the coordinates of the touch in relation to the frame of main view
CGPoint touchLocation = [touch locationInView:self.view];
And then you ask if the location of the touchLocation is within the frame of the buttons frame
if (CGRectContainsPoint(btnOpen.frame, touchLocation))
In another words. You are checking if the touch was within the bounds of the button but you check by the coordinates of the touch made on the main view instead of the button.
So this is what you should do:
CGPoint touchLocation = [touch locationInView:btnOpen];
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
NSLog("Touches Began 1");
for (UITouch *touch in touches) {
//UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (CGRectContainsPoint(btnOpen.frame, touchLocation))
{
NSLog("Touches Began 2");
//dragging = YES;
oldX = touchLocation.x;
oldY = touchLocation.y;
}
}
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
// UITouch *touch = [[event allTouches] anyObject];
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInView:self.view];
if (CGRectContainsPoint(btnOpen.frame, touchLocation))
{
NSLog("Dragging!");
CGRect frame = mainView.frame;
frame.origin.x = mainView.frame.origin.x + touchLocation.x - oldX;
frame.origin.y = mainView.frame.origin.y + touchLocation.y - oldY;
mainView.frame = frame;
}
}
}
Try like this i think it will be helpful to you.

How to restrict uilabel to be dragged within a particular frame only?

I have added one label in imageview and added Pangesture for dragging label.With this code label is dragged within the whole.but i want to restrict the label drag within the frame of uiimageview only.
How can i achieve this? The code for adding lable and gesture is as below.
lblQuote=[[UILabel alloc]init];
lblQuote.frame=CGRectMake(130,380, 400,100);
lblQuote.userInteractionEnabled=TRUE;
lblQuote.backgroundColor=[UIColor clearColor];
lblQuote.userInteractionEnabled=TRUE;
lblQuote.lineBreakMode=UILineBreakModeWordWrap;
lblQuote.font=[UIFont systemFontOfSize:40.0];
lblQuote.tag=500;
lblQuote.text=#"";
CGSize maximumLabelSize = CGSizeMake(296,9999);
CGSize expectedLabelSize = [strQuote sizeWithFont:lblQuote.font
constrainedToSize:maximumLabelSize
lineBreakMode:lblQuote.lineBreakMode];
//adjust the label the the new height.
int nooflines=expectedLabelSize.height/16.0;
lblQuote.numberOfLines=nooflines;
// CGRect newFrame = lblQuote.frame;
//newFrame.size.height = expectedLabelSize.height;
// yourLabel.frame = newFrame;
lblQuote.textAlignment=UITextAlignmentCenter;
UIPanGestureRecognizer *gesture = [[[UIPanGestureRecognizer alloc]
initWithTarget:self
action:#selector(labelDragged:)] autorelease];
[lblQuote addGestureRecognizer:gesture];
- (void)labelDragged:(UIPanGestureRecognizer *)gesture
{
UILabel *label = (UILabel *)gesture.view;
CGPoint translation = [gesture translationInView:label];
// move label
label.center = CGPointMake(label.center.x + translation.x,
label.center.y + translation.y);
// reset translation
[gesture setTranslation:CGPointZero inView:label];
}
I tried moving label on touches event.code is as below:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint pointMoved = [touch locationInView:imgView2];
lblQuote.frame=CGRectMake(pointMoved.x, pointMoved.y, lblQuote.frame.size.width, lblQuote.frame.size.height);
}
But movement is not as smooth as pan gesture recognizer.sometimes touch is in another direction and label movement in some other direction and sometimes more or less movement than touch.
Well this is totally depends on your logics although i wrote a code for you, hope this will help you!!
Make sure your UILabel UserIntraction is set to be YES; and use touch began and touch moved methods instead of pangesture.... see this now
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches]anyObject];
if([touch view] == lblName)
{
NSLog(#"touch on label");
CGPoint pt = [[touches anyObject] locationInView:lblName];
startLocation = pt;
// startLocation is a CGPoint declare globaly in .h..and lblName is your UILabel
}
}
- (void) touchesMoved:(NSSet *)touches withEvent: (UIEvent *)event
{
UITouch *touch = [[event allTouches]anyObject];
if([touch view] == lblName)
{
CGPoint pt = [[touches anyObject] previousLocationInView:lblName];
CGFloat dx = pt.x - startLocation.x;
CGFloat dy = pt.y - startLocation.y;
CGPoint newCenter = CGPointMake(lblName.center.x + dx, lblName.center.y + dy);
//now put if condition for dragging in specific area
CGFloat min_X = lblName.center.x + dx - lblName.frame.size.width/2.0;
CGFloat max_X = lblName.center.x + dx + lblName.frame.size.width/2.0;
CGFloat min_Y = lblName.center.y + dy - lblName.frame.size.height/2.0;
CGFloat max_Y = lblName.center.y + dy + lblName.frame.size.height/2.0;
if((min_X >= imageView.frame.origin.x && max_X <= imageView.frame.origin.x + imageView.frame.size.width) && (min_Y >= imageView.frame.origin.y && max_Y <= imageView.frame.origin.y + imageView.frame.size.height))
{
lblName.center = newCenter;
}
}
}

UIGestureRecognizer Will Not Rotate Sprite - Cocos2d

Does anyone know why it will not rotate the sprite?
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint center = CGPointMake(CGRectGetMidX([[touch view] bounds]), CGRectGetMidY([[touch view] bounds]));
CGPoint firstLocation = [touch previousLocationInView:[touch view]];
CGPoint location = [touch locationInView:[touch view]];
CGPoint currentTouchPoint = [[CCDirector sharedDirector] convertToGL:location];
CGPoint previousTouchPoint = [[CCDirector sharedDirector] convertToGL:firstLocation];
CGPoint line2Start = currentTouchPoint;
CGPoint line1Start = previousTouchPoint;
CGPoint line2End = CGPointMake(center.x + (center.x - line2Start.x), center.y + (center.y - line2Start.y));
CGPoint line1End = CGPointMake(center.x + (center.x - line1Start.x), center.y + (center.y - line1Start.y));
CGFloat a = line1End.x - line1Start.x;
CGFloat b = line1End.y - line1Start.y;
CGFloat c = line2End.x - line2Start.x;
CGFloat d = line2End.y - line2Start.y;
CGFloat line1Slope = (line1End.y - line1Start.y) / (line1End.x - line1Start.x);
CGFloat line2Slope = (line2End.y - line2Start.y) / (line2End.x - line2Start.x);
CGFloat degs = acosf(((a*c) + (b*d)) / ((sqrt(a*a + b*b)) * (sqrt(c*c + d*d))));
CGFloat angleInRadians = (line2Slope > line1Slope) ? degs : -degs;
[g setRotation:angleInRadians];
}
- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
UIGestureRecognizer *recognizer;
[recognizer setState:UIGestureRecognizerStateEnded];
}
G is the sprite in [g setRotation:angleInRadians];
Then, when I add in this
[[touch view] setTransform:CGAffineTransformRotate([[touch view] transform], [grinder rotation])];
It rotates the entire scene! Any help, please?
Thank You!
Dude
below is the link for the ui-kit but it will work fine for cocos2d as well
You need to take care of the coordination system
1)For cocos2d origin is bottom left corner
2)For UIKit origin is upper left corner
"Rotate image by Dragging"
Hope This help You
Good Luck
in the init method pass the following code. this will create a gesture recognizer
UIRotationGestureRecognizer *rotationGesture =
[[UIRotationGestureRecognizer alloc] initWithTarget:self
action:#selector(handleRotate:)];
rotationGesture.delegate = self;
[myImageView addGestureRecognizer:rotationGesture];
[rotationGesture release];
this is the vent that will trigger
- (void)handleRotate:(UIRotationGestureRecognizer *)recognizer {
if(recognizer.state == UIGestureRecognizerStateBegan ||
recognizer.state == UIGestureRecognizerStateChanged)
{
recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform,
recognizer.rotation);
[recognizer setRotation:0];
}
}

iPhone:Programming UISlider to position at clicked location

How to set the slider to clicked position and get the slider value on the clicked location on UISlider in iPhone programming.
i know we can drag the slider to that position but i dont want to do it. Can you please tel me how to set the slider to clicked position? Is this possible to do?
Here is the part "left as a user exercise":
- (void) tapped: (UITapGestureRecognizer*) g {
UISlider* s = (UISlider*)g.view;
if (s.highlighted)
return; // tap on thumb, let slider deal with it
CGPoint pt = [g locationInView: s];
CGFloat percentage = pt.x / s.bounds.size.width;
CGFloat delta = percentage * (s.maximumValue - s.minimumValue);
CGFloat value = s.minimumValue + delta;
[s setValue:value animated:YES];
}
The way I did it is to subclass the slider and check in touchesBegan. If the user taps on the thumb button area (which we track) then ignore the tap, but any where else on the trackbar we do:
:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
// if we didn't tap on the thumb button then we set the value based on tap location
if (!CGRectContainsPoint(lastKnownThumbRect, touchLocation)) {
self.value = self.minimumValue + (self.maximumValue - self.minimumValue) * (touchLocation.x / self.frame.size.width);
}
[super touchesBegan:touches withEvent:event];
}
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value {
CGRect thumbRect = [super thumbRectForBounds:bounds trackRect:rect value:value];
lastKnownThumbRect = thumbRect;
return thumbRect;
}
You can simply add a UITapGestureRecognizer to the slider, then pull out the UIEvent and Touches associated with it to figure out where along the UISlider the tap took place. Then set your slider's value to this calculated value.
UPDATE:
First, setup your slider and add the gesture recognizer to it.
UISlider *slider = [[[UISlider alloc] init] autorelease];
…
<slider setup>
…
UITapGestureRecognizer *gr = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(sliderTapped:)] autorelease];
[slider addGestureRecognizer:gr];
Then implement the selector
- (void)sliderTapped:(UIGestureRecognizer *)gestureRecognizer {
<left as a user excercise*>
}
*Hint: Read the docs to figure out how to get the locationInView extrapolated and figure out what the slider should be
It seems like just subclassing UISlider and returning always true to the beginTracking produce the desired effect.
iOS 10 and Swift 3
class CustomSlider: UISlider {
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
return true
}
}
I was using the subclassed UISlider code to listen to ValueChanged events in ios6> in order to implement a snap-to-grid type of function.
This was broken when upgrading to iOS7 as it no longer fired the UIControlEventsValueChanged. For anyone having the same problem it is fixed by adding a line in the if() as below:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
// if we didn't tap on the thumb button then we set the value based on tap location
if (!CGRectContainsPoint(lastKnownThumbRect, touchLocation)) {
self.value = self.minimumValue + (self.maximumValue - self.minimumValue) * (touchLocation.x / self.frame.size.width);
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
[super touchesBegan:touches withEvent:event];
}
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value {
CGRect thumbRect = [super thumbRectForBounds:bounds trackRect:rect value:value];
lastKnownThumbRect = thumbRect;
return thumbRect;
}
Hope it helps someone :)
I have used this code. Get from: http://imagineric.ericd.net/2012/11/15/uislider-touch-to-set-value/
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(sliderTapped:)];
[slider addGestureRecognizer:gr];
- (void)sliderTapped:(UIGestureRecognizer *)g {
UISlider* s = (UISlider*)g.view;
if (s.highlighted)
return; // tap on thumb, let slider deal with it
CGPoint pt = [g locationInView: s];
CGFloat percentage = pt.x / s.bounds.size.width;
CGFloat delta = percentage * (s.maximumValue - s.minimumValue);
CGFloat value = s.minimumValue + delta;
[s setValue:value animated:YES];
}
Hope this can help you.

How to implement zoom-in/zoom-out effect on a cocos2d sprite image?

I am developing module where-in I pick the image from photo library and put into a sprite. I want to implement zoom-in/zoom-out kind of effect for a sprite image, same like camera album images zoom in/out effect. Could someone please guide me how do i implement it?
I see somewhere is that, I have to detect two touch events in ccTouchBegan and then adjust the sprite's scale size to up or down based on the distance of two fingers touch event values.
Could someone please tell me:
How do i detect two fingers touch values in ccTouchBegan?
How to allow to touch and zoom-in/out of sprite image by user? Please give me samples. I tried already some stuff from this URL, but doesn't work for my requirement.
Thank you.
It would be simpler to use gesture recognizer for zooming:
// on initializing your scene:
UIPinchGestureRecognizer* PinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget: self action: #selector (zoom:)];
[[[Director sharedDirector] openGLView] addGestureRecognizer: PinchGesture];
...
/// zoom callback:
-(void) zoom: (UIPinchGestureRecognizer*) gestureRecognizer
{
if (([gestureRecognizer state] == UIGestureRecognizerStateBegan) || ([gestureRecognizer state] == UIGestureRecognizerStateChanged))
yourSprite.scale = [gestureRecognizer scale];
}
1) First step you need create two variables.
BOOL canPinch;
float oldScale;
2) Use the brigadir's :) answer and add this in your init method
UIPinchGestureRecognizer* pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action: #selector (zoom:)];
[[[CCDirector sharedDirector] openGLView] addGestureRecognizer:pinchGesture];
3)
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray* allTouches = [[event allTouches] allObjects];
UITouch* touch = [touches anyObject];
CGPoint location = [self convertTouchToNodeSpace:touch];;
CGRect particularSpriteRect = CGRectMake(spriteToZoom.position.x-[spriteToZoom boundingBox].size.width/2, spriteToZoom.position.y-[spriteToZoom boundingBox].size.height/2, [spriteToZoom boundingBox].size.width, [spriteToZoom boundingBox].size.height);
if(CGRectContainsPoint(particularSpriteRect, location))
{
if ([allTouches count] == 2)
{
canPinch = YES;
return;
}
else if ([allTouches count] == 1)
{
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
CGPoint oldTouchLocation = [touch previousLocationInView:touch.view];
oldTouchLocation = [[CCDirector sharedDirector] convertToGL:oldTouchLocation];
oldTouchLocation = [self convertToNodeSpace:oldTouchLocation];
CGPoint translation = ccpSub(touchLocation, oldTouchLocation);
[self panForTranslation:translation];
}
}
canPinch = NO;
}
- (void)panForTranslation:(CGPoint)translation
{
CGPoint newPos = ccpAdd(spriteToZoom.position, translation);
spriteToZoom.position = newPos;
}
- (void)zoom: (UIPinchGestureRecognizer*) gestureRecognizer
{
if (canPinch)
{
if (([gestureRecognizer state] == UIGestureRecognizerStateBegan) || ([gestureRecognizer state] == UIGestureRecognizerStateChanged))
{
spriteToZoom.scale = oldScale + [gestureRecognizer scale]-(oldScale != 0 ? 1 : 0);
}
if ([gestureRecognizer state] == UIGestureRecognizerStateEnded)
{
oldScale = spriteToZoom.scale;
}
}
}