Show Hide UIView Twice Every 5 Seconds Using NSTimer - ios

I have a UIView added to a view controller. I want to make it blink twice every 5 seconds.
The following code makes the UIView blink on and off every 1 second:
-(void) showHideView{
[UIView animateWithDuration:1
delay:5
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.myview.alpha = 0;
}
completion:^(BOOL finished){
[UIView animateWithDuration:1
delay:5
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.myview.alpha = 1;
}
completion:nil
];
}
];
}
How can I make the UIView blink twice every 5 seconds? (i.e. a pulse of two blinks)

Since you've flagged this with iOS7, I might suggest keyframe animation:
[UIView animateKeyframesWithDuration:2.5 delay:0.0 options:UIViewKeyframeAnimationOptionRepeat animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.25 animations:^{
self.myview.alpha = 0.0;
}];
[UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.25 animations:^{
self.myview.alpha = 1.0;
}];
} completion:nil];
Tweak total duration (how often the cycle repeats), the relative start times (a % of the total duration), and the relative duration (again, a % of the total duration) as you see fit.

Change both of your delays to zero.
Set both durations to 1.25.
Use a timer to call the method every 2.5 seconds.
How do I use NSTimer?
Edit based on comments:
Use this instead:
-(void) showHideView {
if( self.view.alpha == 1.0 ) alpha = 0.0;
else alpha = 1.0;
}
- (void)timerCallback {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.25 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self showHideView];
});
// repeat above code for 2.5, 3.75, 5.0
}
Make your timer call timerCallback every 5 seconds.

Related

Strange behavior animating a UIView using [UIView animateKeyframesWithDuration]

I'm trying to create an effect where three arrows go from visible to invisible alternatively.
I made a simple algorithm where every arrow would start from a different alpha value (if there is 3 arrows, the first one would start at alpha=1, the second one at alpha=0.6667, the third one at alpha=0.3337). I then start a key frame animation that:
Change the arrow opacity from its current alpha to 0 (the duration is computed)
Set instantly the arrow opacity to 1
Change the arrow opacity from 1 to the first value set
However it seems that some step are skipped for some reason.
A simple example:
[UIView animateKeyframesWithDuration:2 delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear | UIViewKeyframeAnimationOptionRepeat animations:^{
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0 animations:^{
_animatedView.alpha = 0.5;
}];
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.5 animations:^{
_animatedView.alpha = 0;
}];
[UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0 animations:^{
_animatedView.alpha = 1;
}];
[UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.5 animations:^{
_animatedView.alpha = 0.5;
}];
} completion:nil];
In that case it should go to 0.5 instantly, 0.5 to 0 in 1 second, go to 1 instantly, 1 to 0.5 in 1 second. It should therefore do a seamless transition that looks like the view is appearing and disappearing but it looks like the animation gets stuck on alpha=0.5 for a few time.
Theoretically, the effect should be the same as if using this key frame animation:
[UIView animateKeyframesWithDuration:2 delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear | UIViewKeyframeAnimationOptionRepeat animations:^{
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0 animations:^{
_animatedView.alpha = 1;
}];
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:1 animations:^{
_animatedView.alpha = 0;
}];
} completion:nil];
In case you want to animate N views in the same way:
CGFloat count = [self.animatedViews count];
CGFloat period = 1.0f / count;
__weak NSArray *weakViews = self.animatedViews;
[UIView animateKeyframesWithDuration:2.0f delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear | UIViewKeyframeAnimationOptionRepeat animations:^{
for (NSUInteger index = 0; index < count; ++index) {
UIView *animatedView = weakViews[index];
CGFloat startDelay = period * index;
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0 animations:^{
animatedView.alpha = startDelay;
}];
[UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:startDelay animations:^{
animatedView.alpha = 0.0f;
}];
[UIView addKeyframeWithRelativeStartTime:startDelay relativeDuration:0.0f animations:^{
animatedView.alpha = 1.0f;
}];
[UIView addKeyframeWithRelativeStartTime:startDelay relativeDuration:(1.0f - startDelay) animations:^{
animatedView.alpha = startDelay;
}];
}
} completion:nil];

Animation with images when I click on it

I would like that when I click on the image, another image appears for 1 or 2 seconds.
I have two images (UIImage), one for pressed and another for unpressed.
Is it something like this? :
[UIView animateWithDuration: 0.2 delay: 0.0 options: UIViewAnimationOptionAutoreverse animations:^{
pressed.alpha = 1.0;
unPressed.alpha = 0.0;
}completion:^(BOOL finished){
pressed.alpha = 0.0;
unPressed.alpha = 1.0;
}];
But with that I can't see the pressed image.
Edit: My problem is to asign the image to the UIImageView I think, because when I click on it appear the pressed image but then the unPressed image not appear
I would like any similar to that:
[UIView animateWithDuration: 2.0 delay: 0.0 options: UIViewAnimationOptionAutoreverse animations:^{
pressed.alpha = 1.0;
unPressed.alpha = 0.0;
self.imageButton.image = pressed.image;
}completion:^(BOOL finished){
pressed.alpha = 0.0;
unPressed.alpha = 1.0;
self.imageButton.image = unPressed.image;
}];
First off, you set the animation duration to .2 so you may want to increase the duration to 1.0 or 2.0 if you in fact want it to show for 1 or 2 seconds.
Secondly, I'm assuming these images overlap one another, so when both alphas are 1, still only one of the images will be showing. Make sure unPressed is hidden before starting the animation; then make sure pressed is hidden after ending the animation.
unPressed.alpha = 0;
[UIView animateWithDuration: 2.0 delay: 0.0 options: UIViewAnimationOptionAutoreverse animations:^{
pressed.alpha = 1.0;
} completion:^(BOOL finished){
pulsando.alpha = 0.0;
pressed.alpha = 0.0;
unPressed.alpha = 1.0;
}];
(And one more question for you… You said you wanted the image to appear for 1 or 2 seconds. Did you want the image to just appear? Or did you want it to fade in? Just double checking… Because if you just want it to appear, you don't need the animation block.)
Edit: (In response to your edit)
Seems as if you don't need an animation block at all and that you're just trying to have the image appear for 2 seconds. In which case, when the button is pressed, show the image then hide the image after 2 seconds. For example:
- (IBAction)buttonSelected:(UIButton*)sender {
pressed.alpha = 1.0;
unPressed.alpha = 0.0;
[self performSelector:#selector(hidePressedImage) withObject:nil afterDelay:2.0];
}
- (void)hidePressedImage {
pressed.alpha = 0.0;
unPressed.alpha = 1.0;
}
Two images but three variables. Every time you run this function you will see the unPressed image + pressed image (and you will see the one that was added to the view at a later time, since it will be in front).
Maybe pressed image is overlapped by normal? Try following:
[UIView animateWithDuration: 0.2 delay: 0.0 options: UIViewAnimationOptionAutoreverse animations:^{
pressed.alpha = 1.0;
unPressed.alpha = 0.0;
}completion:^(BOOL finished){
pulsando.alpha = 0.0;
unPressed.alpha = 1.0;
pressed.alpha = 0.0;
}];

UIView animation on completion not working properly

I have a problem using a slider to trigger a series of animations, here's the code:
-(void)slideAlpha:(id)sender{
self.bigPhotoViewA.alpha = self.alphaSlider.value;
if (self.alphaSlider.value == 1){
[UIView animateWithDuration:1
animations:^{
self.alphaSlider.alpha = 0;
} completion:nil
];
[self performSelector:#selector(nextPhotoAnimation) withObject:self afterDelay:5.0 ];
}
}
-(void) nextPhotoAnimation{
self.alphaSlider.value = 0;
[UIView animateWithDuration:2
animations:^{
self.bigPhotoViewA.alpha = 0.0;
self.bigPhotoView.alpha = 0.0;
self.smallPhotoView.center = CGPointMake(startX, startY);
}
completion:^(BOOL finished) {
NSLog(#"Animation ended");
self.smallPhotoView.image = ((UIImage *)[smallImagesArray objectAtIndex:imageCount]);
}
];
}
So, when the slider reaches a value of 1, nextPhotoAnimation is launched after a delay. So far so good. The problem comes inside nextPhotoAnimation. The animations block runs ok, but the completion block runs several times every time nextPhotoAnimation is called. I get the NSLog from 6 to 9 times displayed when nextPhotoAnimation starts, and then I get it again at the right time, after 2 seconds.
I've tried to replicate the problem with simpler code and the animation/completion flow works just fine.
Try this in nextPhotoAnimation,
-(void) nextPhotoAnimation{
self.alphaSlider.value = 0;
[UIView animateWithDuration:2
animations:^{
self.bigPhotoViewA.alpha = 0.0;
self.bigPhotoView.alpha = 0.0;
self.smallPhotoView.center = CGPointMake(startX, startY);
}
completion:^(BOOL finished) {
if (finished) {
NSLog(#"Animation ended");
self.smallPhotoView.image = ((UIImage *)[smallImagesArray objectAtIndex:imageCount]);
}
}
];
}
neither you are using
[UIView beginAnimations:nil context:nil];
nor
[UIView commitAnimations];
Best way is to create a UIView and then use the protocols.call your methods using [self YOURMETHOD]; in the View.
:-)

When creating an animation to cause a UIImageView to go up and down (almost float) infinitely, how do I stop a pause at the end of the animation?

Here's the code I'm using to take a UIImageView and make it float up and down.
[UIView animateKeyframesWithDuration:2.0 delay:0.0 options:UIViewKeyframeAnimationOptionRepeat animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.25 animations:^{
self.slider.transform = CGAffineTransformMakeTranslation(0, -5.0);
}];
[UIView addKeyframeWithRelativeStartTime:0.25 relativeDuration:0.5 animations:^{
self.slider.transform = CGAffineTransformMakeTranslation(0, 5.0);
}];
[UIView addKeyframeWithRelativeStartTime:0.75 relativeDuration:0.25 animations:^{
self.slider.transform = CGAffineTransformMakeTranslation(0, 0.0);
}];
} completion:^(BOOL finished) {
}];
However, it comes out looking like this with this delay after the animation ends and before it restarts.
How do I make it fluid?
I'm not sure what effect you're going for exactly, but I think this gives you something like your code does without the delay. I usually do this by animating a constraint, rather than using transforms. In this example, I've made an IBOutlet (topCon) to the constraint to the top of the view:
-(IBAction)floatView:(id)sender {
static int i= 1;
static float duration = .25;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
self.topCon.constant = self.topCon.constant - (5 * i);
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
i = (i == 1 || i == 2)? -2 : 2;
duration = 0.5;
[self floatView:self];
}];
}

IOS Animation not working with my animation block

Im Trying to make a red square move from top of view to a random position at the bottom of the view and the return to the top again at random position.
The app starts with the following code into [super viewLoad]:
[redSquare setCenter:CGPointMake(25,25)];
(with the red square view set 50 x 50, this starts the app with the redsquare in the top left corner).
The first part of the animation works well - the red square animates to a random position to the bottom of the page. But, it then jumps to a random position to the top without animation.
Please help what I'm doing wrong or any other solutions to help with this simple animation.
-(void)moving{
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
} completion:^(BOOL finished) {
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
}];
}
Your completion block simply sets the new position. You aren't animating it back to the top:
Try this, instead
-(void)moving {
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
} completion:^(BOOL finished) {
[UIViewAnimateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
} completion: NULL
}];
}
Edited to add
It's true that sublevels can get confusing, but you can make life simple and less indented if you define the blocks separately from the method.
For example, you could rewrite the above as:
-(void)moving {
workBlk_t animationBlock = ^ {
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
};
void (^completionBlock)(BOOL finished) = ^{
[UIViewAnimateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
} completion : NULL
};
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationCurveEaseIn
animations:animationBlock
completion:completionBlock
}];
}
you should start new animation in completion block for example:
completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,25)];
} completion:^(BOOL finished) {
}];
}];
This part does exactly what you are describing:
completion:^(BOOL finished) {
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
}
I.e. returns the object to the top of the screen after the animiation is completed. This will not be animated, it will happen after the animation is completed, and thus it will be instant.
You need to trigger a new animation after the animation is completed.
To create several nested animation blocks can however become a bit messy, the most clean way is to create another method for animating back and call it when the first animation is completed, like this:
-(void) moveDown{
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
} completion:^(BOOL finished) {
// First animation completed
[self moveBack];
}];
}
-(void) moveBack{
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
} completion:^(BOOL finished) {
// Second animation completed
}];
}

Resources