Drag UIVIew relative to finger - ios

I have a little problem.
I have some UIView and I'm able to drag them with methods touchesBegan and touchesMoved.
My problem is my UIView's coordinates (0,0) is coming under my finger. I would like to avoid that.
Do you know how to do that. I try some things but with no success :(
Thanks a lot !

It will depend on the size of the view but you can probably set the center property to your touch's location.
Animating the center to your tap location
[UIView animateWithDuration:0.25f
delay:0.0f
options:(UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseInOut)
animations:^{
theView.center = tapLocation;
}
completion:NULL]
Instead of just moving the location or translating it, you can animate the view to your current touch in all touches* methods.

when you press down your finger save the point
then measure the speed of the drag, and apply the speed to the position of your view (I translate my view with origin in my exemple)
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSUInteger touchCount = [touches count];
NSUInteger tapCount = [[touches anyObject] tapCount];
NSLog(#"touchesBegan");
NSLog(#"%d touches", touchCount);
NSLog(#"%d taps", tapCount);
UITouch *touch = [touches anyObject];
pNow = [touch locationInView:self];
pLast = [touch locationInView:self];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSUInteger touchCount = [touches count];
NSUInteger tapCount = [[touches anyObject] tapCount];
NSLog(#"touchesMoved");
NSLog(#"%d touches", touchCount);
NSLog(#"%d taps", tapCount);
UITouch *touch = [touches anyObject];
pNow = [touch locationInView:self];
mouseSpeed.x = pNow.x - pLast.x;
mouseSpeed.y = pNow.y - pLast.y;
NSLog(#"mouseSpeed : %f, %f", mouseSpeed.x, mouseSpeed.y);
origin.x += mouseSpeed.x;
origin.y += mouseSpeed.y;
NSLog(#"origin : %f, %f", origin.x, origin.y);
//copy point for the next update
pLast = pNow;
}

Related

Rotating a wheel?

I have read here a few examples about that, but couldn't make it work.
I have some UIView called Wheel , in which i want to rotate while touch and drag.
It should work like a real wheel, so if i touch at some point it will NOT rotate to that point, only when i drag my finger, i will get rotation .
I tried this,but i get a full rotation for every little move i do. I would like to ADD the angel to the view, not ROTATE to the new angel ..
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self];
CGPoint center=wheel.center;
float xLeg = fabs(center.x - touchPoint.x);
float yLeg = fabs(center.y-touchPoint.y);
float angle = atan(xLeg / yLeg);
NSLog(#"%f",angle);
wheel.transform = CGAffineTransformMakeRotation( angleInDegree );
}
This should do the trick. Notice how I store the first touch point in touchesBegan:withEvent:. This allows me to subtract the first touch point from every touch point I get while dragging, and thus gives me the real angle I need to rotate.
EDIT
I've done some adjustments, so that it is now smooth and regular even after several touches.
Demo
WheelViewController.m
#interface WheelViewController () {
CGPoint startPoint;
CGFloat startAngle;
CGFloat endAngle;
}
#end
#implementation WheelViewController
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
startPoint = [touch locationInView:self.view];
startAngle = [self angleForTouchPoint:startPoint] - endAngle;
NSLog(#"\r\nStart angle: %f", startAngle);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
CGFloat touchAngle = [self angleForTouchPoint:touchPoint];
NSLog(#"Touch angle: %f", touchAngle);
self.wheel.transform = CGAffineTransformMakeRotation(fmodf(touchAngle - startAngle, 2 * M_PI));
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
endAngle = [self angleForTouchPoint:touchPoint] - startAngle;
NSLog(#"End angle: %f", endAngle);
}
- (CGFloat)angleForTouchPoint:(CGPoint)touchPoint {
CGPoint center = self.wheel.center;
float xLeg = touchPoint.x - center.x;
float yLeg = touchPoint.y - center.y;
float angle = fmodf(atan(yLeg/xLeg), (2 * M_PI));
if (xLeg < 0) {
angle += M_PI;
}
return angle;
}

Sprite Kit: How to make a node "jump" and also move it left or right, dependant on node position and length of touch?

This is my first post so go easy haha.
I'm new to 'iOS' 'coding', 'Xcode' and 'spritekit'. I'm looking to make an image node "jump" a distance on the positive y-axis if I touch anywhere on the screen, although if I touch somewhere to the left or right if the image and hold for a certain time, it moves in the respective left or right direction, a distance respective to the length of the touch.
Not sure if that's very clear, but any help would be appreciated! Thanks!
You could move a node like this
In touchesEnded: or touchesBegan: method:
{
node.position.y += 50;
}
In order for sprite to move somewhere you could also use actions, there is a family of actions like moveTo action.
I would suggest picking upa tutorial or a book about sprite kit. Good site with free tutorials is raywenderlich.com
Please Try this code :
a sprite move : left/right according to your touch direction anywhere on screen
// CGPoint initialPos; // in .h file
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPt = [touch locationInView:touch.view];
initialPos = [[CCDirector sharedDirector] convertToGL:touchPt];
}
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch=[touches anyObject];
CGPoint currentPos=[myTouch locationInView:[myTouch view]];
currentPos=[[CCDirector sharedDirector] convertToGL:currentPos];
float diffX = currentPos.x - initialPos.x;
float diffY = currentPos.y - initialPos.y;
CGPoint velocity = ccp(diffX, diffY);
initialPos = currentPos;
[Sprite setPosition:ccpAdd([SmileBall position], velocity)];
}
- (void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch=[touches anyObject];
CGPoint currentPos=[myTouch locationInView:[myTouch view]];
currentPos=[[CCDirector sharedDirector] convertToGL:currentPos];
float diffX = currentPos.x - initialPos.x;
float diffY = currentPos.y - initialPos.y;
CGPoint velocity = ccp(diffX, diffY);
initialPos = currentPos;
[Sprite setPosition:ccpAdd([SmileBall position], velocity)];
}
a sprite jump up: according to your touch on screen
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CCSprite *RunningChar;
RunningChar=(CCSprite *)[self getChildByTag:10];
UITouch *touch = [touches anyObject];
CGPoint touchPt = [touch locationInView:touch.view];
touchPt = [[CCDirector sharedDirector] convertToGL:touchPt];
float radian = ccpToAngle(ccpSub(touchPt, prevPoint));
float degrees = CC_RADIANS_TO_DEGREES(radian);
if (degrees >= 22.5 && degrees <= 112.5) // for upward direction :). otherwise you can write only code without ant condition
{
CCJumpTo *jump=[CCJumpTo actionWithDuration:0.7 position:CGPointMake(RunningChar.position.x, 87) height:110 jumps:1];
[RunningChar runAction:seq];
}
else
{
}
}
Try this :)

Scaling custom UIView by CGAffineTransformMakeScale breaks dragging with touchesMoved

I have prepared and checked into GitHub a simple test case for dragging custom UIView:
It works well and dragging is implemented in the Tile.m as:
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
CGPoint previous = [touch previousLocationInView:self];
self.frame = CGRectOffset(self.frame,
(location.x - previous.x),
(location.y - previous.y));
}
However the tiles are too large for my actual game (and I will have to adjust their scaling once the game board in UIScrollView is zoomed anyway):
So I scale my custom UIViews down by calling
tile.transform = CGAffineTransformMakeScale(.5, .5);
The size changes, but the tiles are suddenly dragged "twice as quickly" as needed:
Probably the touchesMoved code (s. above) should be adjusted, but I'm not sure what has been broken there by the transform manipulation?
Nevermind, I have found the solution:
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
CGPoint previous = [touch previousLocationInView:self];
if (!CGAffineTransformIsIdentity(self.transform)) {
location = CGPointApplyAffineTransform(location, self.transform);
previous = CGPointApplyAffineTransform(previous, self.transform);
}
self.frame = CGRectOffset(self.frame,
(location.x - previous.x),
(location.y - previous.y));
}

UIImageView Jumps when Touch Event Occurs

Okay basically what this code currently does is drag an image up and down along the Y axis depending on where the user drags it, and it returns to its original position. My problem is that if someone were to not touch directly on the center of the UIImageView and start dragging it would jolt (very not smooth). Wherever someone is touching the UIImageView and starts dragging the UIImageView jolts a little to go directly on the center of the touch event.
I was thinking about using animation just to move it where the image needs to go, or is there another way?
I apologize if this is an inefficient way to do this. I'm fairly new to the IOS world.
Here's what I have:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//Gets location of UIImageView.
self.originalFrame = self.foregroundImage.frame;
}
//This method is used for moving the UIImageView along the y axis depending on touch events.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if([touch view]==self.foregroundImage) {
CGPoint location = [touch locationInView:self.view];
location.x=self.foregroundImage.center.x;
self.foregroundImage.center=location;
}
}
//This method sets the UIImageView back to its original position.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
CGRect newFrame = self.foregroundImage.frame;
newFrame.origin.y = self.originalFrame.origin.y;
[UIView animateWithDuration:1.1 animations:^{
self.foregroundImage.frame = newFrame;
}];
}
You also need to save the first location in touchesBegan, relative to the parent view. Then, you can use that to change the frame by the difference between the previous location and the new location. Please see the following code.
- (void) touchesBegan: (NSSet*) touches
withEvent: (UIEvent*) event
{
if (touches.count == 1)
{
UITouch* touch = [touches anyObject];
self.touchLocation = [touch locationInView: self.view];
}
}
- (void) touchesMoved: (NSSet*) touches
withEvent: (UIEvent*) event
{
if (touches.count == 1)
{
UITouch* touch = [touches anyObject];
CGPoint newTouchLocation = [touch locationInView: self.view];
if (touch.view == self.foregroundImage)
{
/* Determine the difference between the last touch locations */
CGFloat deltaX = newTouchLocation.x - self.touchLocation.x;
CGFloat deltaY = newTouchLocation.y - self.touchLocation.y;
/* Offset the foreground image */
self.foregroundImage.center
= CGPointMake(self.foregroundImage.center.x + deltaX,
self.foregroundImage.center.y + deltaY);
}
/* Keep track of the new touch location */
self.touchLocation = newTouchLocation;
}
}

Two views with multitouch

I should manage two different views inside my main view; I want detect the exact number of finger inside my views, that is if I have four fingers inside "first view" I want a var that say me a value = 4, and if I have 3 fingers in "second view" I want another var that say me a value = 3. I show you my code that don't work fine.
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
NSLog(#"cgpoint:%f,%f", touchLocation.x, touchLocation.y);
if (CGRectContainsPoint(view1.frame, touchLocation)){
NSLog(#"TOUCH VIEW 1");
totalTouch1 = [[event allTouches]count];
NSLog(#"TOTAL TOUCH 1:%d", totalTouch1);
}
else if (CGRectContainsPoint(view2.frame, touchLocation)){
NSLog(#"TOUCH VIEW 2");
totalTouch2 = [[event allTouches]count];
NSLog(#"TOTAL TOUCH 2:%d", totalTouch2);
}
}
With my code if I begin to lay my finger in "first view", it's all ok, but for example if I lay my fourth finger inside second view my code enter in first "if" and say that my finger is yet in first view. I don't understand the problem.
[[event allTouches] anyObject]; is fetching you only one of the touches.
you need to iterate over all the touches like so:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
int touch1 = 0;
int touch2 = 0;
NSArray *touches = [[event allTouches] allObjects];
for( UITouch *touch in touches ) {
CGPoint touchLocation = [touch locationInView:self.view];
NSLog(#"cgpoint:%f,%f", touchLocation.x, touchLocation.y);
if (CGRectContainsPoint(view1.frame, touchLocation)){
NSLog(#"TOUCH VIEW 1");
touch1 += 1;
NSLog(#"TOTAL TOUCH 1:%d", totalTouch1);
}
else if (CGRectContainsPoint(view2.frame, touchLocation)){
NSLog(#"TOUCH VIEW 2");
touch2 += 1;
NSLog(#"TOTAL TOUCH 2:%d", totalTouch2);
}
}
NSLog(#"Total touches on view 1: %d", touch1);
NSLog(#"Total touches on view 2: %d", touch2);
}

Resources