Move UIView left to right while they move down the screen - ios

I am trying to create an iOS app with blocks floating down the screen(UIViews). I have them floating down the screen but I also want the user to be able to move them on the x axis as they are falling. I tried to do it with the code below but they just fall and don't move left to right. My problem is I am trying to move it with my finger left to right as it is already moving town the screen. How can I adapt the code below to work?
Note: I was able to move the views left to right without them moving down the screen and I was able to move them down the screen without moving them left to right. The problem arises when I combine both.
ANIMATION FOR Y AXIS
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:letView.speed];
[UIView setAnimationDelay:0.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
letView.layer.frame = CGRectMake(letView.layer.frame.origin.x, [[UIScreen mainScreen] bounds].size.height, letView.layer.frame.size.width, letView.layer.frame.size.height);
[UIView commitAnimations];
ANIMATION FOR TOUCH
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
//Goes through an array of views to see which one to move
for (LetterView * view in _viewArray) {
if (CGRectContainsPoint(view.frame, touchLocation)) {
dragging = YES;
currentDragView = view;
[currentDragView.layer removeAllAnimations];
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (dragging) {
CGPoint location = touchLocation;
currentDragView.center = CGPointMake(location.x, currentDragView.center.y);
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
dragging = NO;
[self checkForCorrectWord];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:currentDragView.speed];
[UIView setAnimationDelay:0.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
currentDragView
.layer.frame = CGRectMake(currentDragView.layer.frame.origin.x, [[UIScreen mainScreen] bounds].size.height, currentDragView.layer.frame.size.width, currentDragView.layer.frame.size.height);
[UIView commitAnimations];
}

I've got a demo project that shows you how to make a "boat" animate down the screen in an s-curve, like this:
The solution I use is to make a keyframe animation (actually it's a keyframe animation that forms part of a grouped animation, but you might not need the rest of the grouped animation: it is the keyframe animation that makes the curved path shape). Perhaps you could adapt what I'm doing, modifying it to your own purposes?
The code is available for download here:
https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/ch17p501groupedAnimation
It is discussed in detail in my book. Keyframe animations generally:
http://www.apeth.com/iOSBook/ch17.html#_keyframe_animation
This particular example:
http://www.apeth.com/iOSBook/ch17.html#_grouped_animations

Related

How to get end CGPoint of the screen?

Is there a way to find the endpoint of the screen? Let's say a screen of size (100x100) have the midpoint at (50,) and starting point (0,) and the endpoint as (100,). I can hard code to get the end point based on the device screen size, but that would be a too much work based on assumptions.
I am making a custom UIView animation based on UIBezierPath.
Here is what I am trying to do:
As you can see the animation is stopped after it reaches some point.And I want this point to be the end of the screen,so that UIView is covered whole screen. To be more clear, I drag the UIView to point A, and it animates to point B (end point,so B>A)
I am not sure how to calculate B, so that when I drag UIView to A, it animates to the end of the screen (endpoint of the screen).
Here is the code to get better understanding:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.dragView];
if (touchLocation.x<250) {
if (!startBackSlide) {
_circleDragView.touchdragPoint=touchLocation.y;
_circleDragView.dragToPoint=CGPointMake(touchLocation.x+40, touchLocation.y);
[_circleDragView setNeedsDisplay];
_savedPoint=touchLocation;
}else{
//move the top and bot points backwards along with slide
[self animateCOmpleteBezier:touchLocation];
_circleDragView.touchdragPoint=touchLocation.y;
_circleDragView.dragToPoint=CGPointMake(touchLocation.x+54, touchLocation.y);
[_circleDragView setNeedsDisplay];
_savedPoint=touchLocation;
if (touchLocation.x<20) {
startBackSlide=NO;
snapped=YES;
}
}
}
if (touchLocation.x>=250) {
if (snapped) {
snapped=NO;
//move the top and bottom points to the specified point(In this case the end point)
}
}
}
-(void)animateCOmpleteBezier:(CGPoint) value{
[UIView animateWithDuration:0.01 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
_circleDragView.topWidthPoint=value.x-10;
_circleDragView.botWidthPoint=value.x-10;
[_circleDragView setNeedsDisplay];
} completion:^(BOOL finished) {
}];
}
The endpoint of screen is equal to it's width and height:
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CGPoint endPoint = CGPointMake(screenSize.width, screenSize.height);
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIScreen_Class/#//apple_ref/occ/instp/UIScreen/bounds

UIView Animation Cancel

I want to make a UIView go off the screen upon a touch and come back after a small delay after touch up. So far:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
if ([touch view] == myMainView)
{
[disappearingView.layer removeAllAnimations];
[UIView animateWithDuration:0.5
delay:0
usingSpringWithDamping:0.7
initialSpringVelocity:0.2
options:UIViewAnimationOptionBeginFromCurrentState
animations:^
{
disappearingView.transform = CGAffineTransformMakeScale(0, 0);
}
completion:^(BOOL finished)
{
}];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
if ([touch view] == myMainView)
{
[UIView animateWithDuration:0.5
delay:1
usingSpringWithDamping:0.7
initialSpringVelocity:0.2
options:UIViewAnimationOptionBeginFromCurrentState
animations:^
{
disappearingView.transform = CGAffineTransformMakeScale(1, 1);
}
completion:^(BOOL finished)
{
}];
}
}
Above code works fine so far. However, if the user lift the finger up and touch down again before the 1 second delay expires, disappearing view still comes back, even with the touch down. If you touch down and up randomly, animation is very inconsistent.
I want view to come back only after 1 second and there are no touches at all.
Set a flag in touchesBegan and clear it again in touchesEnded. In your animation block for touchesEnded, check the flag and do not rescale to (1,1) if the flag is set. That way if you get a second touch after the first has ended but before the animation completes, it will not come back.

MKMapView pin drag from another view

I'm thinking about a Google Map street view pin drag and drop system on iOS. The user selects a pin from another view (let's say UINavigationBar) and drag it to a position on map and then drop it.
I'm a bit lost with it. Do you have a workflow for this type of interaction ?
It is quite a complex task but it can be divided into a couple of simple steps.
Make a custom UIView, which after touching will follow the touch movement.
Example
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
_originalPosition = self.view.center;
_touchOffset = CGPointMake(self.view.center.x-position.x,self.view.center.y-position.y);
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint position = [touch locationInView: self.view.superview];
[UIView animateWithDuration:.001
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
self.view.center = CGPointMake(position.x+_touchOffset.x, position.y+_touchOffset.y);
}
completion:^(BOOL finished) {}];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint positionInView = [touch locationInView:self.view];
CGPoint newPosition;
if (CGRectContainsPoint(_desiredView.frame, positionInView)) {
newPosition = positionInView;
// _desiredView is view where the user can drag the view
} else {
newPosition = _originalPosition;
// its outside the desired view so lets move the view back to start position
}
[UIView animateWithDuration:0.4
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
self.view.center = newPosition
// to
}
completion:^(BOOL finished) {}];
}
When user releases the finger, you will have to get the location of the touch.
Calculate the touch location in map view coordinates and place the pin.
Hope it points you to the right direction.

(iOS) Drag and drop, Snap to grid, Check proper area

I've read all the stuff about drag'n'drop and gestureRecognizer but haven't found the solution.
I got "gamefield" 10x10 and I want to implement drag'n'drop with snap to grid and check if element placed on "gamefield".
I got my 8 "TempButtons" added to UIView buttonsSuperView with action:#selector(imageMoved:withEvent:).
- (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event
{
UIControl *control = sender;
originalPosition = [self getButton:sender];
UITouch *touch = [[event allTouches] anyObject];
point = [touch locationInView:control];
float step = 31.0; // Grid step size.
CGPoint center = control.center;
center.x += step * floor((point.x / step));
center.y += step * floor((point.y / step));
control.center = center;
}
It works, I can move any button with grid step 31px. I can place it everywhere, but I have to put it on UIView fieldView. If it placed right there it's OK and I can replace it on another tile. But if I place it outside fieldView the button should return on its place. Something like this:
if ([self.fieldView pointInside:point withEvent:nil])
{
control.center = center;
} else {
[UIView animateWithDuration:0.4
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
control.center = originalPosition;
// to
}
completion:^(BOOL finished) {}];
}
If this code placed on - (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event method it makes button get back to its "originalposition" all the time its moving. But I need to check if its placed properly only on 'touchesEnded'. But that's another method and I don't understand how to realize which button pressed and its original coords to get back if placed improperly.
Maybe there's a better way to use 'UIView' instead of 'UIButton' but I still don't understand how to do that.
Thanks in advance.
Kind Regards,
Nick
Since no one answered my question I've spent some time and found working solution.
- (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event
{
dragObject = sender;
originalPosition = [self getButton:sender];
UITouch *touch = [[event allTouches] anyObject];
point = [touch locationInView:dragObject];
float step = 31.0; // Grid step size.
CGPoint center = dragObject.center;
center.x += step * floor((point.x / step));
center.y += step * floor((point.y / step));
dragObject.center = center;
[sender addTarget:self action:#selector(touchesEnded:withEvent:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (![fieldView pointInside:dragObject.center withEvent:nil])
{
[UIView animateWithDuration:0.4
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
dragObject.center = CGPointMake(originalPosition.x + 15.5, originalPosition.y + 15.5);
}
completion:^(BOOL finished) {}];
}
}
Now it works like charm and I can move along. My buttons moving freely snapped to grid and when pleced outside game field they move back to their original position.
Regards,
Nick

How to move to the next screen when the image drops onto when I tap the button?

I wrote the animation concept in viewDidLoad method i wrote:
scaleFactor=2;
angle=180;
CGRect frame = CGRectMake(10,10,45,45);
UIView *box;
box=[[UIView alloc] initWithFrame:frame];
box.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"images673.png"];
[self.view addSubView:box];
// This code is for the touch event of an object in the screen
// For the object movement i wrote the method which is shown below:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch=[touches anyObject];
CGPoint location=[touch locationInView:self.view];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelegate:self];
[UICiew setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
box.center=location;
[UIView commitAnimations];
}
// And then,now i wrote a button which has to navigate to another class file// General navigation principle i wrote
-(IBAction)settings:(id)sender
{
aScreen *abc=[[aScreen alloc]init];
[self.navigationController pushViewController:abc animated:YES];
[abc release];
}
Now the object is moving where i tap on the screen,but when i tap on the button,the image is not placing on the top of the button.What to do.Please help me.I took an image and then I made some animation for it to move till where I tap in the screen. But at the same time, I took a button and I wrote a button event action in viewcontroller. When I tap the button, the image is not moving onto the button.
What I want to do is if I tap the button, the image has to drop onto the button and it should display the next view controller. Can anyone help me in doing so? How to move to the next screen when the image drops onto when I tap the button?
Im not sure i fully understand the problem without seeing your code but cant you do something like this?
-(ibaction)buttonevent:(id)sender{
cgrect frame = image.frame;
frame.origin.x = button.frame.x;
frame.origin.y = button.frame.y;
image.frame = frame;
image.alpha = 0;
[self pushviewcontroller:newViewcontroller animated:yes];
}
hi try this code i have checked. This is working for me when you check for button and the image you are dragging intersect then fire the method where it moves to next screen
// Handles the continuation of a touch.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"touchesMoved");
UITouch *touch = [touches anyObject];
if ([touch view] == mKey) {
NSUInteger touchCount = 0;
// Enumerates through all touch objects
for (UITouch *touch in touches) {
// Send to the dispatch method, which will make sure the appropriate subview is acted upon
[self dispatchTouchEvent:[touch view] toPosition:[touch locationInView:self.view]];
touchCount++;
}
}
}
// Checks to see which view, or views, the point is in and then sets the center of each moved view to the new postion.
// If views are directly on top of each other, they move together.
-(void)dispatchTouchEvent:(UIView *)theView toPosition:(CGPoint)position
{
// Check to see which view, or views, the point is in and then move to that position.
if (CGRectContainsPoint([mKey frame], position))
{
NSLog(#"touchesMoved");
mKey.center = position;
}
if(CGRectIntersectsRect([mKey frame], [inVisible frame]) && k==0)
{
self.view.userInteractionEnabled=NO;
NSLog(#"thirdPiew frame");
[inVisible setHighlighted:YES];
[inVisible setShowsTouchWhenHighlighted:YES];
k=1;
[self performSelector:#selector(modalPresentationButtonPressed:)];
}
}

Resources