I am trying to have a UIView
animate as a floating object, or as a Balloon :D The UIView
is in the middle of the screen, and I want it to keep floating randomly around its first initiated spot. Not across the screen or anything like that, just floating in the area of 5 pixels around it.
Any suggestions? :D
I tried this:
[UIView animateWithDuration:0.1
delay:0.0
options: UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse | UIViewAnimationOptionAllowUserInteraction
animations:^{
myCircleUIView.transform = CGAffineTransformMakeTranslation([self randomFloatingGenerator], [self randomFloatingGenerator]);
}
completion:NULL];
randomFloatingGenerator
generates a number between -5 and 5. Problem is, it only executes once, and keeps repeating with the same random values.
EDIT1: Now I have tried This
-(void)animationLoop{
[UIView animateWithDuration:1.0
animations: ^{ myCircleUIView.transform = CGAffineTransformMakeTranslation([self randomFloatingGenerator], [self randomFloatingGenerator]); }
completion:
^(BOOL finished) {
[UIView animateWithDuration:1.0
animations:^{ myCircleUIView.transform = CGAffineTransformMakeTranslation(0,0);
}
completion:
^(BOOL finished) {[self animationLoop];}];
}];
But it is still not working, the animation is.... Cracky... I think I am doing some stupid mistake that I need a second set of eyes to help me with.
EDIT2: Fixed it.
-(void)animationLoop{
CGPoint oldPoint = CGPointMake(myCircleUIView.frame.origin.x, myCircleUIView.frame.origin.y);
[UIView animateWithDuration:1.0
animations: ^{ myCircleUIView.frame = CGRectMake(myCircleUIView.frame.origin.x + [self randomFloatingGenerator], myCircleUIView.frame.origin.y + [self randomFloatingGenerator], myCircleUIView.frame.size.width, myCircleUIView.frame.size.height); }
completion:
^(BOOL finished) {
[UIView animateWithDuration:1.0
animations:^{ myCircleUIView.frame = CGRectMake(oldPoint.x, oldPoint.y, myCircleUIView.frame.size.width, myCircleUIView.frame.size.height);}
completion:
^(BOOL finished) {[self animationLoop];}];
}];
}
Thanks for the help anyone.
EDIT 3:
Someone posted an enhanced code.
@Shamy's solution, improved, fixed and CPU safe.
-(void)animateFloatView:(UIView*)view{
// Abort the recursive loop
if (!view)
return;
CGPoint oldPoint = CGPointMake(view.frame.origin.x, view.frame.origin.y);
[UIView animateWithDuration:0.6
animations: ^{ view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y - 15, view.frame.size.width, view.frame.size.height); }
completion:
^(BOOL finished) {
if (finished) {
[UIView animateWithDuration:0.6
animations:^{ view.frame = CGRectMake(oldPoint.x, oldPoint.y, view.frame.size.width, view.frame.size.height);}
completion:
^(BOOL finished2) {
if(finished2)
[self animateFloatView:view];
}];
}
}];
}
Whenever you want to stop the animation (necessary when leaving the View Controller), call the function using nil , as this:
[self recursiveFloatingAnimation:nil];
Not stoping the animation will cause the recursive loop to run infinitely and overwhelm the CPU stack.
It will behave in that way. As you are repeating the animation not the function. So it will repeat same animation every time you set at first call. Do it like:
@interface AAViewController ()
@property (nonatomic, strong) UIView * floatingView;
@end
@implementation AAViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_floatingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
[_floatingView setBackgroundColor:[UIColor redColor]];
[self.view addSubview:_floatingView];
[self circleUIViewFloating];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Circle UIView floating
- (void) circleUIViewFloating {
[UIView animateWithDuration:2.0
animations:^{
_floatingView.transform = CGAffineTransformMakeTranslation([self randomFloatingGenerator : 270], [self randomFloatingGenerator:480]);
} completion:^(BOOL finished) {
[self circleUIViewFloating];
}];
}
- (int) randomFloatingGenerator : (int) max{
return arc4random() % max;
}
Here is complete running project for this.
Swift 4
UIView.animate(withDuration: 0.6, delay: 0.1, options: [.autoreverse, .repeat], animations: {
self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y - 15, width: self.frame.size.width, height: self.frame.size.height)
},completion: nil )
-(void)animationLoop{
CGPoint oldPoint = CGPointMake(myCircleUIView.frame.origin.x, myCircleUIView.frame.origin.y);
[UIView animateWithDuration:1.0
animations: ^{ myCircleUIView.frame = CGRectMake(myCircleUIView.frame.origin.x + [self randomFloatingGenerator], myCircleUIView.frame.origin.y + [self randomFloatingGenerator], myCircleUIView.frame.size.width, myCircleUIView.frame.size.height); }
completion:
^(BOOL finished) {
[UIView animateWithDuration:1.0
animations:^{ myCircleUIView.frame = CGRectMake(oldPoint.x, oldPoint.y, myCircleUIView.frame.size.width, myCircleUIView.frame.size.height);}
completion:
^(BOOL finished) {[self animationLoop];}];
}];
}
Swift 2.1 Version Here:
func animateFloatView(view: UIView?) {
// Abort the recursive loop
guard let view = view else { return }
let oldPoint: CGPoint = CGPointMake(view.frame.origin.x, view.frame.origin.y)
UIView.animateWithDuration(0.6, animations: {() -> Void in
view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y - 15, view.frame.size.width, view.frame.size.height)
}, completion: {(finished: Bool) -> Void in
if finished {
UIView.animateWithDuration(0.6, animations: {() -> Void in
view.frame = CGRectMake(oldPoint.x, oldPoint.y, view.frame.size.width, view.frame.size.height)
}, completion: {(finished2: Bool) -> Void in
if finished2 {
self.animateFloatView(view)
}
})
}
})
}
Swift 3.1:
func animateFloatView(_ view: UIView?) {
guard let view = view else { return }
let oldYCoordinate = view.center.y
UIView.animate(withDuration: 0.6, animations: {
view.center.y -= 15
}, completion: { _ in
UIView.animate(withDuration: 0.6, animations: {
view.center.y = oldYCoordinate
}, completion: { _ in
self.animateFloatView(view)
})
})
}
You can achieve the hovering or floating effect using CABasicAnimation
.
You will have to include the QuartzCore
framework to use this.
Swift 4.2:
import QuartzCore
let hover = CABasicAnimation(keyPath: "position")
hover.isAdditive = true
hover.fromValue = NSValue(cgPoint: CGPoint.zero)
hover.toValue = NSValue(cgPoint: CGPoint(x: 0.0, y: -5.0))
hover.autoreverses = true
hover.duration = 0.8
hover.repeatCount = Float.infinity
myCustomView.layer.add(hover, forKey: "hoverAnimation")
Make sure to remove the animation when the view is no longer being shown.
override func viewWillDisappear(_ animated: Bool) {
// Stop animating when view is going to disappear
myCustomView.layer.removeAllAnimations()
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.