I'm trying to change the text of an UILabel with a little transition (fade out, change text, fade in) but I'm facing some problems. Here is my code:
- (void) setTextWithFade:(NSString *)text {
[self setAlpha:1];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:.25];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeDidStop:finished:context:)];
[self setAlpha:0];
[UIView commitAnimations];
}
- (void)fadeDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.25];
[self setAlpha:1];
[UIView commitAnimations];
}
This code "works" (the effect is working well), but what I can't figure out is how to change the label text in the "fadeDidStop" function... How can I "pass" the text variable from my first function to the second?
Thanks in advance
You pass the text in the context:
[UIView beginAnimations:nil context:text];
Then in your fadeDidStop method:
NSString *text = (NSString*) context;
Be mindful when passing objects in the context, make sure they are retained properly.
...
[UIView beginAnimations:nil context:[text retain]];
...
- (void)fadeDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
self.text = (NSStrinhg *)context;
[context release];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.25];
[self setAlpha:1];
[UIView commitAnimations];
}
maybe the simpliest way is to declare NSString object in your .h file and use it to store text to change.
Related
Good Moscow evening to everyone!
I'm still unfamiliar with principles of iPhone animation (btw, does anybody know a big and nice tutorial on this?), but in my project I want to do button "highlighted-not highlighted" flicker to notify the user that its label has changed.
This code doesn't do anything (it's just a fragment of flicker animation):
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 0.5];
[button setHighlighted: YES];
[UIView commitAnimations];
And this one highlights the button, but does not do it in an animated form:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 0.5];
[button setSelected: YES];
[UIView commitAnimations];
Can anyone help me and say:
What's wrong with this code?
What would fix the problem?
----------------------------------- UPDATE ------------------------------
I tried that kind of code, but it doesn't work either:
// ------------------------
// --- animation ----------
// ------------------------
- (void)animateIn
{
[UIView beginAnimations: #"animateIn" context:nil];
[UIView setAnimationDuration: 0.2];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
[control setBackgroundColor:[UIColor blackColor]];
[UIView commitAnimations];
}
- (void)animateOut
{
[UIView beginAnimations: #"animateOut" context:nil];
[UIView setAnimationDuration: 0.2];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
[control setBackgroundColor:[UIColor whiteColor]];
[UIView commitAnimations];
}
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
if([animationID isEqualToString: #"animateIn"])
{
[self animateOut];
return;
}
else if ([animationID isEqualToString: #"animateOut"])
{
cycleCount++;
if(cycleCount < 3)
[self animateIn];
else
cycleCount = 0;
return;
}
}
#end
//isFlickerOn is declared in .h file as BOOL isFlickerOn;
//flickerTimer is declared in .h file as NSTimer *flickerTimer;
//flickerCount is declared in .h file as int flickerCount;
//control is a UILabel, UIButton background color is really hard to notice
//especially the roundedRect UIButton, so I just flickered a UILabel's textColor
-(void)flickerOn {
if (flickerCount < 5)
{
flickerCount++;
if (!isFlickerOn)
{
[control setTextColor:[UIColor yellowColor]];
isFlickerOn = YES;
}
else
{
[control setTextColor:[UIColor blueColor]];
isFlickerOn = NO;
}
}
else
{
[flickerTimer invalidate];
}
}
-(void)flickerAnimation {
flickerCount = 0;
flickerTimer = [NSTimer scheduledTimerWithTimeInterval:0.3f target:self selector:#selector(flickerOn) userInfo:nil repeats:YES];
}
Not all attributes of a UIView are animatable - and I do not believe "highlighted" or "selected" are.
Typically, it's usable for non-boolean values, like "center", "alpha", "frame" and "bounds".
Try tweaking the alpha instead, and you'll see it will work.
You need to create a callback method that executes when the first animation finishes. You use that callback to do create a deselected animation. Keep in mind that there is no gradual "selection state" like there is for transparency. You have to use the
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
[UIView beginAnimations:#"animateIn" context:NULL];
From Apple's docs:
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
Your method must take the following arguments:
animationID
An NSString containing an optional application-supplied identifier. This is the identifier that is passed to the beginAnimations:context: method. This argument can be nil.
finished
An NSNumber object containing a Boolean value. The value is YES if the animation ran to completion before it stopped or NO if it did not.
context
An optional application-supplied context. This is the context data passed to the beginAnimations:context: method. This argument can be nil.
When the animation is finished, the callback animationDidStop is called and passed in the string #"animateIn". You can use that method to check which animation was called and handle that there.
I have put a line of code inside the UIAnimation block. And the next line comes after the animation block. I want the second line only to be executed after the time interval of the first animation block.
Eg:-
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:0.5];
//First line comes here
[self.view addSubview:subView];
[UIView commitAnimations];
Then the 2nd line
[subView2 removeFromSuperView];
I want the 2nd line only to be executed after the 0.5 second interval of the animation action. Is it possible to do like this?
You can set a delegate for animation and remove subview in its method:
...
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
[UIView setAnimationDelegate:self];
//First line comes here
[self.view addSubview:subView];
[UIView commitAnimations];
...
Then in delegate's animation did stop handler remove your 2nd subview:
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
if ([finished boolValue])
[subView2 removeFromSuperview];
}
I have a simple animation which simply modify the position of a button:
[UIView beginAnimation:nil context:nil];
[UIView setAnimationsDuration:3.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
mybutton.frame = CGREctMake(20, 233, 280, 46);
[UIView commitAnimations];
I want to perform some other animations when this one is finish, how to do that?
You could look at setAnimationBeginsFromCurrentState:. All the animations are run in their own threads, so [UIView commitAnimations] is a nonblocking call. So, if you begin another animation immediately after committing the first one, after appropriately setting whether or not it begins from the current state, I think you'll get the behavior you want. To wit:
[UIView beginAnimation:nil context:nil];
// set up the first animation
[UIView commitAnimations];
[UIView beginAnimation:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:NO];
// set up the second animation
[UIView commitAnimations];
Alternately, you could provide a callback by doing something like
[UIView beginAnimation:nil context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)
// set up the first animation
[UIView commitAnimations];
//...
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
// set up the second animation here
}
a code segment for getting start.. setup initial (the first) animation:
- (void) aniPath:(AnimationPath *) path
{
[UIView beginAnimations:path->aniname context:path];
[UIView setAnimationDuration:path->interval];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(aniDone:finished:context:)];
// your initial animation
[UIView commitAnimations];
}
chains to another animation when the first is done:
- (void) aniDone:(NSString *) aniname finished:(BOOL) finished context:(void *) context
{
AnimationPath *path = (AnimationPath *) context;
if ([aniname isEqualToString:path->aniname]) {
[UIView beginAnimations:path->aniname context:context];
[UIView setAnimationDuration:path->interval];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(aniDone:finished:context:)];
// more animations, even recursively
[UIView commitAnimations];
}
}
Use the +[UIVIew setAnimationDelegate:] and +[UIView setAnimationDidStopSelector:] methods to configure your class to receive a message when the animation ends.
it quite easier.
you can just
- (void)animationDidContiune:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
UIView *currentObj = context;
[self callTheAnimation: currentObj];
}
you can easily loop the animation.
To end it - I would create an animationDidEnded and use it instead of animationDidContiune
once you want to stop it (like simple if in animation that chooses either to contiune or end).
HF.
AND WHAT's IMPORTANT:
use this type of animating meths:
- (void)callTheAnimation:(UIView*)itemView
{
[UIView beginAnimations:#"animation" context:itemView];
.
.
.
}
they are quite flexible - you can animate whatever here due to hierarchy of the objects.
I'm a newbie and I need some help.
I want to display a popup image over a given UIView, but I would like it to behave like the UIAlertView or like the Facebook Connect for iPhone modal popup window, in that it has a bouncy, rubbber-band-like animation to it.
I found some code on the net from someone who was trying to do something similar. He/she put this together, but there was no demo or instructions.
Being that I am so new, I don't have any idea as to how to incorporate this into my code.
This is the routine where I need the bouncy image to appear:
- (void) showProductDetail
{
. . .
////////////////////////////////////////////////////////////////////////
// THIS IS A STRAIGHT SCALE ANIMATION RIGHT NOW. I WANT TO REPLACE THIS
// WITH A BOUNCY RUBBER-BAND ANIMATION
_productDetail.transform = CGAffineTransformMakeScale(0.1,0.1);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
_productDetail.transform = CGAffineTransformMakeScale(1,1);
[UIView commitAnimations];
}
. . .
}
This is the code I found:
float pulsesteps[3] = { 0.2, 1/15., 1/7.5 };
- (void) pulse {
self.transform = CGAffineTransformMakeScale(0.6, 0.6);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:pulsesteps[0]];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(pulseGrowAnimationDidStop:finished:context:)];
self.transform = CGAffineTransformMakeScale(1.1, 1.1);
[UIView commitAnimations];
}
- (void)pulseGrowAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:pulsesteps[1]];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(pulseShrinkAnimationDidStop:finished:context:)];
self.transform = CGAffineTransformMakeScale(0.9, 0.9);
[UIView commitAnimations];
}
- (void)pulseShrinkAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:pulsesteps[2]];
self.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
}
Thanks in advance for any help that you can give me.
It's pretty simple. In your showProductDetail method, you start an animation block, then set the _productDetail.transform property, and then commit the block. This is what makes the animation happen.
The code that you found is designed to do a chain of such animations, but the property being modified is on self instead of on _productDetail. If _productDetail is an instance of a class that you created yourself, you can put the animation code inside that class.
Otherwise, just move the code inside the pulse method to the showProductDetail method, and put the two other methods below that method. Replace self.transformwith _productDetail.transformin all three methods.
Currently I have this code that works fine
[UIView setAnimationDidStopSelector:#selector(animationDone:finished:context:)];
- (void)animationDone:(NSString *)animationID finished:(BOOL)finished context:(void *)context {
// do stuff here
}
Logging the value of animationID gives me a null.
How can I pass value to the #selector?
I tried
[UIView setAnimationDidStopSelector:#selector(animationDone:#"animation1"finished:context:)];
That gives me an error.
Thanks,
Tee
The string passed to the selector is the one you use in this method call:
[UIView beginAnimations:#"your_animation_name_here" context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationFinished:finished:context:)];
// whatever changes here
[UIView commitAnimations];
Afterwards, you can do this:
- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context
{
if ([animationID isEqualToString:#"your_animation_name_here"])
{
// something done after the animation
}
}