Moving an object randomly around the screen - iphone

I'm trying to animate a UIButton to move randomly around the screen in different directions. The code below is kind of working. The button will begin moving along a random path, however, it then just continues to move back and forth between point A and point B.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationRepeatCount:1000];
[UIView setAnimationRepeatAutoreverses:YES];
CGFloat x = (CGFloat) (arc4random() % (int) self.view.bounds.size.width);
CGFloat y = (CGFloat) (arc4random() % (int) self.view.bounds.size.height);
CGPoint squarePostion = CGPointMake(x, y);
button.center = squarePostion;
[UIView commitAnimations];
How can I get it to keep moving to a new random point every time it changes directions, instead of simply moving back and forth?
Thanks!

try this:
-(void)animationLoop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
// remove:
// [UIView setAnimationRepeatCount:1000];
// [UIView setAnimationRepeatAutoreverses:YES];
CGFloat x = (CGFloat) (arc4random() % (int) self.view.bounds.size.width);
CGFloat y = (CGFloat) (arc4random() % (int) self.view.bounds.size.height);
CGPoint squarePostion = CGPointMake(x, y);
button.center = squarePostion;
// add:
[UIView setAnimationDelegate:self]; // as suggested by #Carl Veazey in a comment
[UIView setAnimationDidStopSelector:#selector(animationLoop:finished:context:)];
[UIView commitAnimations];
}
and just add a counter (int) inside the method to check if it's executed more than 1000 times, if wanna stop it...

Swift 5 example of making one animation
#objc func didBecomeActive() {
DispatchQueue.main.async {
self.startAnimationCalm()
}
}
func startAnimation() {
let animatedShadow = UIView(frame: CGRect(origin: CGPoint(x: 10, y: 10), size: CGSize(width: 20, height: 20)))
animatedShadow.clipsToBounds = true
animatedShadow.layer.cornerRadius = 20/2
animatedShadow.backgroundColor = UIColor.green
animatedShadow.layer.borderWidth = 0
self.view.addSubview(animatedShadow)
UIView.animate(withDuration: 5, delay: TimeInterval(0), options: [.repeat, .curveEaseIn], animations: { () -> Void in
let randomX = CGFloat.random(in: 14 ... 200)
let randomY = CGFloat.random(in: 20 ... 600)
animatedShadow.center = CGPoint(x: animatedShadow.frame.origin.x + randomX, y: animatedShadow.frame.origin.y + randomY)
self.view.layoutIfNeeded()
}, completion: { finished in
})
}

Related

Rotating image round a fix point

Firstly I am new to Objective C, any help will be most appreciated. I trying to write a Gauge app (which will eventually show the Angle of the phone). The issue I have is when I rotate the Needle image, it rotates to the correct angle, but not from the Anchor point - the image moves position. Even when I move, say from 0 dregs to 90 and back to 0, the image is does not end up back in its original position! The code I am using is below: .
(PS I am only currently only running the app on the simulator)
*** Rotate Invoked by ....
// Rotate Image
[self rotateImage:_imgNeedle duration: vAnimationDuration curve: UIViewAnimationCurveLinear degrees:vValue];
-(void)rotateImage:(UIImageView *)image
duration:(NSTimeInterval)duration
curve:(int)curve
degrees:(CGFloat)degrees
{
// Setup the animation
[self setAnchorPoint:CGPointMake(.44,.85) forView:image];
// image.transform = CGAffineTransformMakeRotation(d2r(degrees));
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
[UIView setAnimationBeginsFromCurrentState:YES];
// The transform matrix
CGAffineTransform transform = CGAffineTransformMakeRotation(d2r(degrees));
image.transform = transform;
// Commit the changes
[UIView commitAnimations];
}
// Set Anchor Point
-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view
{
CGPoint newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x, view.bounds.size.height * anchorPoint.y);
CGPoint oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x, view.bounds.size.height * view.layer.anchorPoint.y);
newPoint = CGPointApplyAffineTransform(newPoint, view.transform);
oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform);
CGPoint position = view.layer.position;
position.x -= oldPoint.x;
position.x += newPoint.x;
position.y -= oldPoint.y;
position.y += newPoint.y;
view.layer.position = position;
view.layer.anchorPoint = anchorPoint;
}
I am not sure about the layer position, but when I change the anchorPoint, the frame changes, so I will adjust the frame.
-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view
{
CGPoint newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x, view.bounds.size.height * anchorPoint.y);
CGPoint oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x, view.bounds.size.height * view.layer.anchorPoint.y);
newPoint = CGPointApplyAffineTransform(newPoint, view.transform);
oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform);
/*
CGPoint position = view.layer.position;
position.x -= oldPoint.x;
position.x += newPoint.x;
position.y -= oldPoint.y;
position.y += newPoint.y;
view.layer.position = position;
*/
view.frame = CGRectOffset(view.frame, newPoint.x-oldPoint.x, newPoint.y-oldPoint.y);
view.layer.anchorPoint = anchorPoint;
}
And also if you want to go back to the original position with multiple calling of rotateImage, I think you should only set the anchor point once before that. Since if you make two separate animation with the same rotateImage method, the anchor point will be recalculated with your current implementation.
-(void)rotateImage:(UIImageView *)image
duration:(NSTimeInterval)duration
curve:(int)curve
degrees:(CGFloat)degrees
{
// Setup the animation
// [self setAnchorPoint:CGPointMake(.44,.85) forView:image];
// image.transform = CGAffineTransformMakeRotation(d2r(degrees));
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
[UIView setAnimationBeginsFromCurrentState:YES];
// The transform matrix
CGAffineTransform transform = CGAffineTransformMakeRotation(d2r(degrees));
image.transform = transform;
// Commit the changes
[UIView commitAnimations];
}

UIView animateWithDuration interfering with other CGRectMake

I have a CGRectMake that used to jump an image to a different position
image.frane=CGRectMake( x,y,w,h);
Then I wanted to translate and scale a Label (on the same ViewController) to another position
CGPoint newCenter = CGPointMake(x,y);
[UIView animateWithDuration: 1.0
delay: 0
options: 0
animations:^{label.center = newCenter ; label.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.2, 0.2);}
completion:^(BOOL finished) {
label.transform = CGAffineTransformMakeScale(1.0, 1.0);
label.alpha = 0;
}
];
The problem I'm having is when I use the animateWithDuration the image doesn't move but the Label does. If I comment out the animation the image moves again. Am I doing something wrong?
try this bellow code...
[UIView animateWithDuration:1.0f animations:^{
imageView.frame = CGRectMake(newCenter.x, newCenter.y, imageView.frame.size.width, imageView.frame.size.height);
}];
Also you can move UIImageView or anything else with this bellow code... i use this code for scroll the UIScrollView when keyboard appear.. i add the code with your requirement..
UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0f];
imageView.frame = CGRectMake(newCenter.x, newCenter.y, imageView.frame.size.width, imageView.frame.size.height);
[UIView commitAnimations];
i hope this helpful to you...

Layer Position jumps at start of (Core) Animation

So, I'm trying to create a tile flipping effect, like on Windows Phone 7.
So far I have the following code, but I have a couple of queries.
CALayer *layer = self.theRedSquare.layer;
CATransform3D initialTransform = self.theRedSquare.layer.transform;
initialTransform.m34 = 1.0 / -1000;
[UIView beginAnimations:#"Scale" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
layer.transform = initialTransform;
layer.anchorPoint = CGPointMake(-0.3, 0.5);
CATransform3D rotationAndPerspectiveTransform = self.theRedSquare.layer.transform;
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, M_PI , 0 , -self.theRedSquare.bounds.size.height/2, 0);
layer.transform = rotationAndPerspectiveTransform;
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
1. How come my my red square (a simple UI view) translates to the right at the start of the animation?
2. For the anchor point is it possible to set a position on the parent view? At the moment I am arbitrarily setting it relative to the current view.
Thanks in advance for any pointers.
Before animation
During animation (notice the square has shifted right)
After animation (notice the square has shifted right)
Video added: example video
-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view
{
CGPoint newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x, view.bounds.size.height * anchorPoint.y);
CGPoint oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x, view.bounds.size.height * view.layer.anchorPoint.y);
newPoint = CGPointApplyAffineTransform(newPoint, view.transform);
oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform);
CGPoint position = view.layer.position;
position.x -= oldPoint.x;
position.x += newPoint.x;
position.y -= oldPoint.y;
position.y += newPoint.y;
view.layer.position = position;
view.layer.anchorPoint = anchorPoint;
}
-(void)animateView:(UIView *)theRedSquare
{
CALayer *layer = theRedSquare.layer;
CATransform3D initialTransform = theRedSquare.layer.transform;
initialTransform.m34 = 1.0 / -1000;
[self setAnchorPoint:CGPointMake(-0.3, 0.5) forView:theRedSquare];
[UIView beginAnimations:#"Scale" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
layer.transform = initialTransform;
CATransform3D rotationAndPerspectiveTransform = theRedSquare.layer.transform;
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, M_PI , 0 , -theRedSquare.bounds.size.height/2, 0);
layer.transform = rotationAndPerspectiveTransform;
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
}
Taken from This, and slightly tweaked.. Hopefully it helps
Changing my CALayer's anchorPoint moves the view
If you make the square its own view, flipping is built-in
[UIView beginAnimations:#"flip" context:nil];
[UIView setAnimationDuration:.35f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromLeft
forView:self.window cache:YES];
// change to the new view (make this one hidden, the other not)
[UIView commitAnimations];
The acceptable range of the anchorPoint of a CALayer is [0,1]. In your case, where you are attempting to flip around the Y axis, your layer's anchor point should be [0, 0.5].

(Scale) Zoom into a UIView at a point

Something I don't understand about transformations. I want to zoom in to say the top right corner of a UIView (the main view). I use CGAffineTransformScale and have tried both setting the center/anchorPoint as well as CGAffineTransformMakeTranslation to no avail.
I can't figure out how to set the translation properly so that it will zoom in on this point.
CGAffineTransform tr = CGAffineTransformScale(self.view.transform, 2, 2);
[UIView animateWithDuration:2.5 delay:0 options:0 animations:^{
self.view.transform = tr;
self.view.center = CGPointMake(480,0);
} completion:^(BOOL finished) {}];
You are setting the center of the view to the top right corner. That means you're zooming in on somewhere to the lower left of the center.
Try this
CGAffineTransform tr = CGAffineTransformScale(self.view.transform, 2, 2);
CGFloat h = self.view.frame.size.height;
[UIView animateWithDuration:2.5 delay:0 options:0 animations:^{
self.view.transform = tr;
self.view.center = CGPointMake(0,h);
} completion:^(BOOL finished) {}];
This will set the center of the blown-up view to the left bottom corner, effectively zooming in with the top right corner fixed.
This code doesn't have the height hardcoded, which is a little more portable (to an iPad of iPhone 5).
You need to first save h before setting the transform property, because after that you should not rely on the value of frame.
edit
To make it work for any scale s, use this:
CGFloat s = 3;
CGAffineTransform tr = CGAffineTransformScale(self.view.transform, s, s);
CGFloat h = self.view.frame.size.height;
CGFloat w = self.view.frame.size.width;
[UIView animateWithDuration:2.5 delay:0 options:0 animations:^{
self.view.transform = tr;
self.view.center = CGPointMake(w-w*s/2,h*s/2);
} completion:^(BOOL finished) {}];
To make it work for bottom left, use this:
CGFloat s = 3;
CGAffineTransform tr = CGAffineTransformScale(self.view.transform, s, s);
CGFloat h = self.view.frame.size.height;
CGFloat w = self.view.frame.size.width;
[UIView animateWithDuration:2.5 delay:0 options:0 animations:^{
self.view.transform = tr;
self.view.center = CGPointMake(w*s/2,h-h*s/2);
} completion:^(BOOL finished) {}];
To make it work for bottom right, use this:
CGFloat s = 3;
CGAffineTransform tr = CGAffineTransformScale(self.view.transform, s, s);
CGFloat h = self.view.frame.size.height;
CGFloat w = self.view.frame.size.width;
[UIView animateWithDuration:2.5 delay:0 options:0 animations:^{
self.view.transform = tr;
self.view.center = CGPointMake(w-w*s/2,h-h*s/2);
} completion:^(BOOL finished) {}];
See also: How to scale (zoom) a UIView to a given CGPoint
In case anyone is still interested, here is the Swift 3.0 solution, to which I added the possibility to fade out correctly.
(I know there are two enums missing, but the code is still readable and I think you will get the concept)
func animateZoom(direction: ZoomDirection, type: ZoomType, duration: Double = 0.3, scale: CGFloat = 1.4) {
var cx, cy: CGFloat
var tr: CGAffineTransform = CGAffineTransform.identity
if (type == .IN) { tr = self.transform.scaledBy(x: scale, y: scale) }
let h: CGFloat = self.frame.size.height;
let w: CGFloat = self.frame.size.width;
if (type == .IN) {
switch direction {
case .LEFT_DOWN:
cx = w*scale/2
cy = h-h*scale/2
break
case .LEFT_UP:
cx = w*scale/2
cy = h*scale/2
break
case .RIGHT_UP:
cx = w-w*scale/2
cy = h*scale/2
break
case .RIGHT_DOWN:
cx = w-w*scale/2
cy = h-h*scale/2
break
}
} else {
cx = w/scale/2
cy = h/scale/2
}
UIView.animate(withDuration: duration, delay: 0, options: [.curveEaseInOut], animations: {
self.transform = tr
self.center = CGPoint(x: cx, y: cy)
}, completion: { finish in })
}

Strange bug with View interaction

I have to views. One on top of the other.
But i cannot click the subviews of the top view until I set the alpha of the bottom view to 0.0.
Why would that be? Is there some kind of work around?
Code involved
-(void)setUpOpponentsCardStartingPosition
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
CGRect newF = deckCard.view.frame;
newF.origin.x -= CGRectGetWidth(newF);
deckCard.view.layer.transform = CATransform3DIdentity;
deckCard.view.frame = newF;
deckCard.view.alpha = 0.0;
[UIView commitAnimations];
playersCard.view.layer.transform = CATransform3DScale(CATransform3DIdentity, 0.97,
0.97, 1.0);
opponentsCard.view.layer.transform = CATransform3DRotate(CATransform3DIdentity, -
35*M_PI/180, 0.0, 1.0, 0.0);
opponentsCard.view.layer.transform =
CATransform3DScale(opponentsCard.view.layer.transform, 0.65, 0.675, 1.0);
opponentsCard.view.layer.transform =
CATransform3DTranslate(opponentsCard.view.layer.transform, 400, 0, 0);
opponentsCard.view.hidden = NO;
}
if i comment out the deckCard.view.alpha = 0.0; it wont let me interact with playersCard. This makes no sense to me since playersCard is on top.
Here is setup code for deckCard
-(void)setupDeckInBackground
{
deckCard.view.alpha = 0.0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
deckCard.view.frame = playersCard.view.frame;
deckCard.view.alpha = 1.0;
deckCard.view.layer.zPosition = -1;
deckCard.view.layer.transform = CATransform3DMakeRotation(M_PI/180*5, 0, 0, 1);
deckCard.view.layer.transform = CATransform3DScale(deckCard.view.layer.transform,
1.0, 1.0, 1.0);
deckCard.view.layer.transform =
CATransform3DTranslate(deckCard.view.layer.transform, 0, 0, -25);
[UIView commitAnimations];
}
Thanks
-Code
I found that the solution was to use
deckCard.view.userInteractionEnabled = NO;
Thanks,
-Code