Reputation: 375
I have a layer that I want to show when the user does an action, and hide after he is done. The layer is then shown again if the user does the action again.
In order for the UI to not go berserk with animations, I want:
what is the best way to do this?
I tried this, but this won't work properly (lot of noise with the layer blinking ):
- (void)hideHintLayer:(bool)hide
{
if(hide)
{
CABasicAnimation *animation = [CABasicAnimation animation];
animation.beginTime = CACurrentMediaTime() + 1.0f;
animation.duration = 1.0f;
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
animation.keyPath = @"opacity";
animation.fromValue = @(1.0f);
animation.toValue = @(0.0f);
[layer addAnimation:animation forKey:nil];
}
else
{
layer.opacity = 1.0f;
}
}
Upvotes: 4
Views: 1611
Reputation: 437422
If you want to stop an animation, you can just do
[layer removeAllAnimations];
If you want to know the current alpha
during the animated hiding of the view (so that you can reverse the animation, starting from the right place, you can do:
CALayer *presentationLayer = layer.presentationLayer;
CGFloat startingAlpha = presentationLayer.opacity;
You can then set the alpha to go from startingAlpha
to 1.0 to animate the unhide without flickering the screen.
You can do the actual animations using block based animation, or I guess you could use CABasicAnimation
, though I'm not sure why you would.
So, for example, you could do something like the following (in my example, I have a "show" button). I'm using block animations, but I suspect it would work fine for CABasicAnimation
, too:
- (IBAction)onPressShowButton:(id)sender
{
[self showAndScheduleHide];
}
- (void)showAndScheduleHide
{
[UIView animateWithDuration:1.0
animations:^{
self.containerView.alpha = 1.0;
}
completion:^(BOOL finished) {
[self scheduleHide];
}];
}
- (void)show
{
[UIView animateWithDuration:1.0
animations:^{
self.containerView.alpha = 1.0;
}
completion:nil];
}
- (void)scheduleHide
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:@selector(startToHide)
userInfo:nil
repeats:NO];
}
- (void)startToHide
{
self.timer = nil;
self.hiding = YES;
[UIView animateWithDuration:5.0
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
self.containerView.alpha = 0.0;
}
completion:^(BOOL finished) {
self.hiding = NO;
}];
}
You can then have some utility method for reversing it or rescheduling a hide in progress:
- (void)reverseAndPauseHide
{
// if we have a "hide" scheduled, then cancel that
if (self.timer)
{
[self.timer invalidate];
self.timer = nil;
}
// if we have a hide in progress, then reverse it
if (self.hiding)
{
[self.containerView.layer removeAllAnimations];
CALayer *layer = self.containerView.layer.presentationLayer;
CGFloat currentAlpha = layer.opacity;
self.containerView.alpha = currentAlpha;
[self show];
}
}
Then, the question is when you know to call this reverseAndPauseHide
and when to scheduleHide
again. So, for example, you could handle touches:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
[self reverseAndPauseHide];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
[self scheduleHide];
}
Upvotes: 3