This question already has answers here:
Animating only the image in UIBarButtonItem
(4 answers)
Closed 8 years ago.
I have an UIButton created by the following code
button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:[UIImage imageNamed:#"refresh_icon.png"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:#"reload_selected.png"] forState:UIControlStateSelected];
[button addTarget:self action:#selector(buttonAction:)forControlEvents:UIControlEventTouchUpInside];
[button setFrame:CGRectMake(0, 0, 20 , 20)];
Here when it's clicked the selector buttonAction is called and I am animating the button by a 360 degree rotation like this
- (void) buttonAction : (id) sender {
NSLog(#"Reload Button Clicked");
[self runSpinAnimationOnView:self.button duration:1.0 rotations:1.0 repeat:0];
}
- (void) runSpinAnimationOnView:(UIView*)view duration:(CGFloat)duration rotations:(CGFloat)rotations repeat:(float)repeat;
{
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 /* full rotation*/ * rotations * duration ];
rotationAnimation.duration = duration;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = repeat;
[view.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
}
It's working good but it's not that I actually want. I want that , when my button is clicked then button will take the image "reload_selected.png" (which I set for UIControlStateSelected) as background and then run the animation. When the animation is finished then button will have to return to it's actual background ("refresh_icon.png") again.
Can anyone suggest some change in code that will help me achieve the action I described above ? Thanks in advance for your help.
Can you try like this,
[UIView animateWithDuration:YOURDURATION
delay:0
options:(UIViewAnimationOptionCurveLinear)
animations:^ {
[button setImage:[UIImage imageNamed:#"reload_selected.png"] forState:UIControlStateSelected];
button.transform = CGAffineTransformRotate(CGAffineTransformIdentity,M_PI * 2);
}
completion:^(BOOL finished) {
[button setImage:[UIImage imageNamed:#"refresh_icon.png"] forState:UIControlStateNormal];
}
];
Instead of using Core Animation, you can use animateWithDuration:animations:completion: method of UIView. This method allows you to specify a completion block whick you can use to reset the image once the animation is completed.
EDIT:
Do something like
[view animateWithDuration:duration animations:^{
//Do your animations here
} completion: ^(BOOL finished){
if(finished) {
//reset the image
}
}];
To specify the animations you might want to animate the view's transform property using CGAffineTransformRotate.
Related
I am using a UISlider in my app where I add max and min image for slider. Every thing works good but look at the image below. When I click on button the animation starts and values on label change but the animation on slider directly jumps to 6 which you can see it and the same thing happens when the slider reaches it max value(100) from 96 the slider min image(orange color) disappears and the label continues to show values 97..98..99..100.
Here's the code snippet for reference :
- (void)viewDidLoad
{
[super viewDidLoad];
UIImage *sliderMinimum = [[UIImage imageNamed:#"slider_max"] stretchableImageWithLeftCapWidth:14 topCapHeight:0];
[self.slider setMinimumTrackImage:sliderMinimum forState:UIControlStateNormal];
UIImage *sliderMaximum = [[UIImage imageNamed:#"slider_min"] stretchableImageWithLeftCapWidth:14 topCapHeight:0];
[self.slider setMaximumTrackImage:sliderMaximum forState:UIControlStateNormal];
}
- (IBAction)btnClicked:(id)sender
{
[self.slider setValue:0 animated:true];
[self setSliderValue:2];
}
- (void)setSliderValue:(float)value
{
[UIView animateWithDuration:0.2 animations:^{
[self.slider setValue:value animated:true];
} completion:^(BOOL finished) {
self.lblSliderValue.text = [NSString stringWithFormat:#"%0.0f", self.slider.value];
if (self.slider.value != self.slider.maximumValue) {
[self setSliderValue:value+1];
}
}];
}
Try with this:
[slider addTarget:self
action:#selector(roundValue:)
forControlEvents:UIControlEventValueChanged];
And in the roundValue function set the value:
- (void)roundValue{
[slider setValue:((int)((slider.value + 0) / 1) * 1) animated:NO];
}
I am having the code below, which is an animation of a UIButton. But when the button is pressed, i want the animation stop at once and do something else, while if the animation continue it does something else. My problem is that even i press the button, the animation continue and it will do both step 1 and 2.
What am i missing in the code?
int frame1 = 600;
int frame2 = 100;
hit11 = [[UIButton alloc]initWithFrame:CGRectMake((arc4random() % (frame1 - frame2)+frame2),200,20,20)];
[hit11 addTarget:self action:#selector(hit:) forControlEvents:UIControlEventTouchUpInside];
[hit11 setBackgroundImage:[UIImage imageNamed:#"touchrightdown.png"] forState:UIControlStateNormal];
[self.view addSubview:hit11];
[UIView animateWithDuration:2.0 delay:0.1 options:UIViewAnimationCurveEaseIn | UIViewAnimationOptionAllowUserInteraction animations:^{
hit11.transform = CGAffineTransformMakeScale(7,7);
hit11.alpha=0.5;
} completion:^(BOOL finished) {
if (finished) {
//DO STEP 2.
hit11.hidden=YES;
}
NSLog(#"got hit");
}];
-(void) hit:(UIButton*)sender{
NSLog(#"1/10");
//DO STEP 1.
}
Try adding this:
[sender.layer removeAllAnimations];
in your hit:(UIButton*)sender method.
my goal is to create a simple popover view over a bar button in my tool bar. So apparently Apple doesn't want me to create this on my iPhone. But i already saw something familiar on other apps.
So instead of using the UIPopOver thing from Apple, i like to create an UIView which appears when the bar button is clicked. And disappears when it is clicked again. It would be over the top if i also could create the little arrow which points to the button (you know which arrow i mean :D). But this is not relevant at this time. I just want to create this "popover appears and disappears with the same button". My "solution" right know is not a solution:
- (IBAction)buttonPressed:(id)sender
{
UIView *myPopOverView = [[UIView alloc] initWithFrame:CGRectMake(25, 25, 500, 250)];
myPopOverView.alpha = 0.0;
myPopOverView.layer.cornerRadius = 5;
myPopOverView.layer.borderWidth = 1.5f;
myPopOverView.layer.masksToBounds = YES;
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(testNSLog)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Show myPopOverView" forState:UIControlStateNormal];
button.frame = CGRectMake(10, 10, 100, 30);
[myPopOverView addSubview:button];
[self.view addSubview:myPopOverView];
[UIView animateWithDuration:0.4 animations:^{
[myPopOverView setAlpha:1.0];
} completion:^(BOOL finished) {}];
}
So i don't have a clue on how to do that with this code fragment. It appears right away as i want. But i don't know how to create this toggle. I tried with a simple Bool-If-Toggle, but it didn't work. And i don't really know how to remove it from my view either.
Can you guys help me with this?
Thanks in advance!
Ok i solved it.
i defined a UIView in the .h-File and instantiate it in ViewDidLoad, then i did:
- (IBAction)buttonPressed:(id)sender
{
if (showedOptions == NO) {
[self.view addSubview:self.popoverView];
[UIView animateWithDuration:0.4 animations:^{
[self.popoverView setAlpha:1.0];
} completion:^(BOOL finished) {}];
showedOptions = YES;
return;
} else {
showedOptions = NO;
[self.popoverView removeFromSuperview];
}
}
Hello guys I am new to xcode and I am trying to animate balloons on touch by changing its images: this is my code:
now the problem i am facing is its not animating images means the animation timer is not working: please guide me what should i do to animate the images with time: if I am not doing it properly then please guide me that how can i do it by NSTimer?
-(void)baloonbursting:(UIButton *)button withEvent:(UIEvent *)event{
if ([[UIImage imageNamed:#"redbaloons.png"] isEqual:button.currentImage]) {
NSLog(#"em redbaloons.png");
UIImage *bubbleImage3 = [UIImage imageNamed:#"redburst.png"];
[button setImage:bubbleImage3 forState:UIControlStateNormal];
}
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView animateWithDuration:1.0f animations:^(){
// define animation
if ([[UIImage imageNamed:#"redburst.png"] isEqual:button.currentImage]) {
NSLog(#"em redbaloons.png");
UIImage *bubbleImage3 = [UIImage imageNamed:#"redburst2.png"];
[button setImage:bubbleImage3 forState:UIControlStateNormal];
}
}
completion:^(BOOL finished){
// after the animation is completed call showAnimation again
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionAllowUserInteraction animations:^{
} completion:^(BOOL finished){
if (finished) {
[button removeFromSuperview];
}}];
}];
}
I want you to give you a solution to show you the right direction to think. That is, why I developed a small test project in Xcode and I controlled that this code really works.
First: forget NSTimers for this animation!
The idea is, that you "play" around with subviews, because you can change their alpha properties from 0.0 (invisible) to 1.0 (fully opaque), which are supported by the SDK's view animations.
Please change the image names according to your own file names (I've used my own here).
The following method checks, if the button's image is that one that shall invoke an animation - exactly what you did before. If this condition is met, it visually animates the change of the button's image to another image:
- (IBAction)balloonBursting:(UIButton *)sender
{
BOOL doAnimate = NO;
UIImageView *ivOldBubbleImage;
UIImageView *ivNewBubbleImage;
if ([[UIImage imageNamed:#"BalloonYellow.png"] isEqual:sender.currentImage]) {
NSLog(#"will animate");
doAnimate = YES;
UIImage *newImage = [UIImage imageNamed:#"BalloonPurple.png"];
ivNewBubbleImage = [[UIImageView alloc] initWithImage:newImage];
ivNewBubbleImage.alpha = 0.0;
ivOldBubbleImage = sender.imageView;
[sender addSubview:ivNewBubbleImage];
}
if (doAnimate) {
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView animateWithDuration:1.0f animations:^(){
// define animation
ivOldBubbleImage.alpha = 0.0;
ivNewBubbleImage.alpha = 1.0;
}
completion:^(BOOL finished){
[sender setImage:ivNewBubbleImage.image forState:UIControlStateNormal];
[ivNewBubbleImage removeFromSuperview];
}];
}
}
I was wondering if it was possible to apply a flashing animation to a UIButton. I have searched but only found the code for a pulse animation which changes the size of my UIButton continuously. I instead was thinking about some kind of flashing animation to alert the user he has to press the button. The only approach to the problem I can think of is by changing the alpha constantly using:
[self setAlpha:0.5];
...but it won't be as visible as a flashing button.
Perhaps not the best way, and doesn't really allow you to stop the flashing... but this is simple, works, and does not hinder user interaction:
- (void)viewDidLoad
{
[self flashOn:myButton];
}
- (void)flashOff:(UIView *)v
{
[UIView animateWithDuration:.05 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^ {
v.alpha = .01; //don't animate alpha to 0, otherwise you won't be able to interact with it
} completion:^(BOOL finished) {
[self flashOn:v];
}];
}
- (void)flashOn:(UIView *)v
{
[UIView animateWithDuration:.05 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^ {
v.alpha = 1;
} completion:^(BOOL finished) {
[self flashOff:v];
}];
}
Reading all the answers so far I found following solution. It repeats a number of times and does the job for me.
CGFloat oldAlpha = v.alpha;
CGFloat minAlpha = 0.2;
enum UIViewAnimationOptions options = UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionAutoreverse | UIViewAnimationOptionCurveEaseInOut;
[UIView animateWithDuration:.3 delay:0.3 options:options animations:^{
[UIView setAnimationRepeatCount:4];
v.alpha = minAlpha;
}
completion:^(BOOL finished) {
v.alpha = oldAlpha;
}];
Try this one:
call this method when you want blink/flash the button
blinkTimer=[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(toggleButtonImage:) userInfo:nil repeats:YES];
and write this method
- (void)toggleButtonImage:(NSTimer*)timer
{
if(toggle)
{
[blinkBtn setImage:[UIImage imageNamed:#"ButtonImage.png"] forState: UIControlStateNormal];
}
else
{
[blinkBtn setImage:[UIImage imageNamed:#"ButtonImage1.png"] forState: UIControlStateNormal];
}
toggle = !toggle;
}
in .h write this one
NSTimer *blinkTimer;
BOOL toggle;
and invalidate the timer where you want to stop the flashing/blinking
[blinkTimer invalidate];
Maybe you could have two different .png files [buttons] that cycle back and forth in a loop, assign the same action to them, and have this kick off whenever a certain condition is met. I'd write the code out but it would likely be full of errors. Have you tried something like that?
I did this by creating my own control, subclassing UIControl since Apple doesn't recommend screwing with the view hierarchy of UIButton. I add a background imageView representing the standard background image of the button, and a "glowing" imageView above the background to represent the lit-up state, and toggle its opacity to make it pulse.
I additionally toggle the layer's shadow opacity to make it glow.
Initializing Code:
- (void)TS_commonButtonInit
{
UIImage *shoutoutBackground = [UIImage imageNamed:#"root-navigation-bar-share-button"];
UIImage *shoutoutHighlightedBackground = [UIImage imageNamed:#"root-navigation-bar-share-button-highlighted"];
UIImage *shoutoutPulseImage = [UIImage imageNamed:#"root-navigation-bar-share-button-glowing"];
shoutoutBackground = [shoutoutBackground stretchableImageWithLeftCapWidth:7 topCapHeight:0];
shoutoutHighlightedBackground = [shoutoutHighlightedBackground stretchableImageWithLeftCapWidth:7 topCapHeight:0];
shoutoutPulseImage = [shoutoutPulseImage stretchableImageWithLeftCapWidth:7 topCapHeight:0];
[[self backgroundView] setImage:shoutoutBackground];
[[self backgroundView] setHighlightedImage:shoutoutHighlightedBackground];
[self setGlowingImage:shoutoutPulseImage];
[self setExclusiveTouch:YES];
[self addSubview:[self backgroundView]];
[self addSubview:[self glowingImageView]];
[[self layer] setShadowColor:[[UIColor colorWithHexString:#"ffc521" alpha:1] CGColor]];
[[self layer] setShadowOpacity:0];
[[self layer] setShadowRadius:5];
[[self layer] setShadowOffset:CGSizeMake(0, 0)];
[[self layer] setShadowPath:[[UIBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:6] CGPath]];
}
Pulsing Code:
- (void)pulse:(NSInteger)numberOfTimes
{
CGFloat pulseLength = .8;
[[self glowingImageView] setAlpha:0];
CABasicAnimation *pulseAnimation = [CABasicAnimation animationWithKeyPath:#"opacity"];
[pulseAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[pulseAnimation setDuration:pulseLength];
[pulseAnimation setRepeatCount:numberOfTimes];
[pulseAnimation setAutoreverses:YES];
[pulseAnimation setFromValue:#(0)];
[pulseAnimation setToValue:#(1)];
[pulseAnimation setRemovedOnCompletion:YES];
[[self layer] setShadowOpacity:0];
CABasicAnimation *shadowAnimation = [CABasicAnimation animationWithKeyPath:#"shadowOpacity"];
[shadowAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[shadowAnimation setDuration:pulseLength];
[shadowAnimation setRepeatCount:numberOfTimes];
[shadowAnimation setAutoreverses:YES];
[shadowAnimation setFromValue:#(0)];
[shadowAnimation setToValue:#(1)];
[shadowAnimation setRemovedOnCompletion:YES];
[[[self glowingImageView] layer] addAnimation:pulseAnimation forKey:#"opacity"];
[[self layer] addAnimation:shadowAnimation forKey:#"shadowOpacity"];
}