Adding animation to UIButton between states - ios

I have a button with two states (i toggle the button using the "selected" state). I would like to animate the transition between the states when user clicks on the button.
I have a list of images that form the animation - what would be the logic to add the animations to the button?

subclass UIButton, override setSelected method this way:
-(void)setSelected:(BOOL)selected{
self.enabled = NO; // disable btn until animation finished
[self setBackgroundImage:nil forState:UIControlStateNormal];
[self setBackgroundImage:nil forState:UIControlStateSelected];
NSArray *imageNames;
// hardcoded frames sequences is for clarity ofcourse =)
if (selected){
// direct frames sequence
imageNames = #[#"normalBG", #"frame0", #"frame1", #"frame2", #"selectedBG"];
} else {
// reversed frames sequence
imageNames = #[#"selectedBG", #"frame2", #"frame1", #"frame0", #"normalBG"];
}
NSTimeInterval animationDuration = (float)imageNames.count/YOUR_ANIMATION_FPS;
NSMutableArray *imageBuffer = [NSMutableArray arrayWithCapacity:imageNames.count];
NSMutableArray *timeBuffer = [NSMutableArray arrayWithCapacity:imageNames.count];
[imageNames enumerateObjectsUsingBlock:^(NSString *name, NSUInteger idx, BOOL *stop) {
[imageBuffer addObject:(__bridge id)[UIImage imageNamed:name].CGImage];
[timeBuffer addObject:#( (float)(idx)/(imageNames.count-1) )];
}];
NSArray *images = [NSArray arrayWithArray:imageBuffer];
NSArray *times = [NSArray arrayWithArray:timeBuffer];
imageBuffer = nil;
timeBuffer = nil;
CAKeyframeAnimation *framesAnimation = [CAKeyframeAnimation animationWithKeyPath:#"contents"];
framesAnimation.values = images;
framesAnimation.keyTimes = times;
framesAnimation.calculationMode = kCAAnimationLinear;
framesAnimation.removedOnCompletion = YES;
framesAnimation.fillMode = kCAFillModeForwards;
framesAnimation.duration = animationDuration;
[CATransaction begin];
[CATransaction setCompletionBlock:^{
[super setSelected:selected];
if (selected){
[self setBackgroundImage:[UIImage imageNamed:#"selectedBG"] forState:UIControlStateSelected];
[self setBackgroundImage:nil forState:UIControlStateNormal];
} else {
[self setBackgroundImage:nil forState:UIControlStateSelected];
[self setBackgroundImage:[UIImage imageNamed:#"normalBG"] forState:UIControlStateNormal];
}
self.enabled = YES;
}];
[self.layer addAnimation:framesAnimation forKey:#"contents"];
[CATransaction commit];
}
don't forget to set the initial background image, i.e. [self setBackgroundImage:[UIImage imageNamed:#"normalBG"] forState:UIControlStateNormal]; in button's init method

Related

Scrollview should start from where I left it last time

I have a scrollview(timesScrollView) which is added as a subview on a view(dropDownView).The view is hidden until a particular button is pressed, when that button is pressed view will appear.
(IBAction)how_many_times_btn_click:(id)sender{
if(howMany==false){
for(UIView *view in dropDownView.subviews)
{
[view removeFromSuperview];
}
howMany=true;
duration=false;
how_many_times_btn.backgroundColor=[UIColor colorWithRed:130/255.0f green:189/255.0f blue:31/255.0f alpha:1.0f];
durationBtn.backgroundColor=[UIColor colorWithRed:62/255.0f green:67/255.0f blue:79/255.0f alpha:1.0f];
startBtn.backgroundColor=[UIColor colorWithRed:62/255.0f green:67/255.0f blue:79/255.0f alpha:1.0f];
dropDownView.hidden=NO;
dropDownView.frame=CGRectMake(0, 0, self.view.frame.size.width,70);
dropDownView.backgroundColor=[UIColor colorWithRed:37/255.0f green:42/255.0f blue:54/255.0f alpha:1.0f];
//dropDownView.backgroundColor=[UIColor whiteColor];
targetLbl=[[UILabel alloc]init];
targetLbl.frame=CGRectMake(0, 30, dropDownView.frame.size.width,30);
targetLbl.text=#"TARGET";
targetLbl.textColor=[UIColor whiteColor];
targetLbl.font=[UIFont boldSystemFontOfSize:22];
targetLbl.textAlignment=NSTextAlignmentCenter;
how_many_Lbl=[[UILabel alloc]init];
how_many_Lbl.frame=CGRectMake(0, targetLbl.frame.origin.y+targetLbl.frame.size.height, dropDownView.frame.size.width, 20);
how_many_Lbl.textAlignment=NSTextAlignmentCenter;
how_many_Lbl.text=#"HOW MANY TIMES WILL YOU DO IT?";
how_many_Lbl.textColor=[UIColor colorWithRed:65/255.0f green:71/255.0f blue:80/255.0f alpha:1.0f];
how_many_Lbl.font=[UIFont systemFontOfSize:10.0f];
hideViewBtn=[UIButton buttonWithType:UIButtonTypeCustom];
hideViewBtn.frame=CGRectMake(dropDownView.frame.size.width-30,20,20,20);
[hideViewBtn setImage:[UIImage imageNamed:#"Close Icon [ x ]"] forState:UIControlStateNormal];
[hideViewBtn addTarget:self action:#selector(hideView) forControlEvents:UIControlEventTouchUpInside];
//hideViewBtn.backgroundColor=[UIColor whiteColor];
self.timesScroll=[[LTInfiniteScrollView alloc] initWithFrame:CGRectMake(0, how_many_Lbl.frame.origin.y+how_many_Lbl.frame.size.height+16, dropDownView.frame.size.width, 102)];
//self.timesScroll.backgroundColor=[UIColor whiteColor];
self.timesScroll.verticalScroll=NO;
self.timesScroll.dataSource=self;
self.timesScroll.maxScrollDistance=5;
self.timesScroll.contentInset=UIEdgeInsetsMake(0, self.timesScroll.frame.size.width/2-31, 0,self.timesScroll.frame.size.width/2-31 );
self.timesScroll.userInteractionEnabled=YES;
self.timesScroll.exclusiveTouch=YES;
dropDownView.frame=CGRectMake(0, 0, self.view.frame.size.width,_timesScroll.frame.origin.y+_timesScroll.frame.size.height+20);
[self viewWillAppear:YES];
[dropDownView addSubview:targetLbl];
[dropDownView addSubview:how_many_Lbl];
[dropDownView addSubview:hideViewBtn];
[dropDownView addSubview:_timesScroll];
}
else
{
[self hideView];
}
}
The method above is what I am using to create view.
Now my problem is that when that particular button(how_many_times_btn) is pressed again all views are first removed then added as you can see and scrollview starts from initial position but I want it show from where I left it last time how_many_times_btn was clicked.
Hope you can understand What I am trying to say....if not I am happy to elaborate furthur.
you can get the last position by delegate methods
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
nslog(#"%f %f",scrollView.contentOffset.x,scrollView.contentOffset.y);
}
and store the x and y value and set
scrollView.contentOffset = CGPointMake(x,y);
You can save contentOffsetto one variable of CGPoint. And use this variable 's value later to scroll the UIScrollview.
Something like below line of code :
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
contentOffset = scrollView.contentOffset;
}
When button pressed write below line of code:
self.timesScroll .contentOffset = contentOffset;
I'm using LTInfiniteScrollview in which there is a method 'reloadDataWithInitialIndex'
-(void)reloadDataWithInitialIndex:(NSInteger)initialIndex
{
for (UIView *view in self.scrollView.subviews) {
[view removeFromSuperview];
}
self.views = [NSMutableDictionary dictionary];
self.visibleViewCount = [self.dataSource numberOfVisibleViews];
self.totalViewCount = [self.dataSource numberOfViews];
[self updateSize];
_currentIndex = initialIndex;
self.scrollView.contentOffset = [self contentOffsetForIndex:_currentIndex];
[self reArrangeViews];
[self updateProgress];}
This method is called in 'viewWillAppear'
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.viewSize = CGRectGetWidth(self.view.frame) / Number_of_visibleViews;
self.timesScroll.delegate=self;
[self.timesScroll reloadDataWithInitialIndex:howIndex];}
I just passed previous index value here.

uiview animation delays starting

I'm trying to display a continuously scrolling 'movie credits'. The VC code is shown below. The problem is that there is a ~12 second delay before the animation starts. Once the animation starts, the delay is not repeated between calls. The same behavior is seen on the simulator and a iPhone5.
An added bit of interest: When the VC pops, the app goes crazy with cpu use (100%+)... my laptop will hit 200°.
Apparently it's the initial animation that is not firing. If the completion block is commented out, no animation ever happens. So the 12 second delay is actually the first run of the animation not doing anything then the second invocation actually makes something happen on the screen.
Can someone explain what I'm doing wrong or point me to the appropriate docs.
- (void)loopCredits
{
CGRect startFrame = _creditsView.frame;
CGRect endFrame = CGRectMake(0, -568, 320, 568);
[UIView animateWithDuration:10.0
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
self.creditsView.frame = endFrame;
}
completion:^(BOOL finished) {
self.creditsView.frame = startFrame;
[self performSelector:#selector(loopCredits) withObject:nil afterDelay:0.0];
}
];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.navigationController.navigationBarHidden = NO;
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// [self loopCredits];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self createInfoString];
self.creditsView.attributedText = self.text;
[self loopCredits];
}
- (void)createInfoString
{
NSString* path = [[NSBundle mainBundle] pathForResource:#"InfoPageText" ofType:#"plist"];
NSURL* pathURL = [[NSURL alloc] initFileURLWithPath:path];
NSArray* temp = [NSArray arrayWithContentsOfURL:pathURL];
NSUInteger strLength = [[temp objectAtIndex:0] length];
self.text = [[NSMutableAttributedString alloc] initWithString:[temp objectAtIndex:0]];
UIFont* font = [UIFont fontWithName:#"Chalkduster" size:18.0f];
UIColor* textColor = [UIColor colorWithRed:250.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1];
[_text addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, strLength)];
[_text addAttribute:NSForegroundColorAttributeName value:textColor range:NSMakeRange(0, strLength)];
}

Button image array animation with delay after every cycle

I am working on with a simple animation that I have 10 button and "on click" of one button ( for example 5) all button should start animate one by on but they are animating the same time, please let me know what can be done or ..... Thanks
NSMutableArray* imagesArray = [[NSMutableArray alloc] init];
for (int images = 0; images < 15; images++) {
UIImage* buttonImage = [UIImage imageNamed:[NSString stringWithFormat:#"aaqqq00%02d.png", images]];
[imagesArray addObject:buttonImage];
}
NSArray* reversedAnim = [[imagesArray reverseObjectEnumerator] allObjects];
int buttonTag = button.tag;
for (int images = 1; images <= 10; images++) {
UIButton *animButton = (UIButton *)[self.view viewWithTag:images];
if (images <= buttonTag) {
animButton.imageView.animationImages = imagesArray;
[animButton setImage:
[UIImage imageNamed:#"aaqqq0014.png"] forState:UIControlStateNormal];
animButton.adjustsImageWhenHighlighted = NO;
animButton.imageView.animationDuration = 1; //whatever you want (in seconds)
animButton.imageView.animationRepeatCount = 1;
[animButton.imageView startAnimating];
} else {
if (currentButtonTag_ >= images) {
animButton.imageView.animationImages = reversedAnim;
[animButton setImage:
[UIImage imageNamed:#"aaqqq0000.png"] forState:UIControlStateNormal];
animButton.adjustsImageWhenHighlighted = NO;
animButton.imageView.animationDuration = 0.2; //whatever you want (in seconds)
animButton.imageView.animationRepeatCount = 1;
[animButton.imageView startAnimating];
}
}
}
As you iterate through your loop, have a variable that holds the desired delay, and add to it at the end of each loop. We'll call this delay.
Now, instead of calling:
[animButton.imageView startAnimating];
Do this:
[animButton.imageView performSelector:#selector(startAnimating) withObject:nil afterDelay:delay];
And each button will start animating after the accumulated delay.
You need to give some delay time and duration time.
[UIView animateWithDuration:0.6
delay:2.0
options: UIViewAnimationCurveEaseOut
animations:^{S1Button.frame = CGRectMake(20, 10, 50, 10);S1buttonA.alpha = 0;}
completion:nil];
Set this for every animation.

Revmob more games button in cocos2d

Hi i am using revmob in my game . I have integrated full screen but i cant call more games screen. I have CCMenuItemImage and on its selector i have called
[RevMobAds openAdLinkWithAppID:#"000000000000000"];
its opening itunes. But i want to call [[RevMobAds session] button]; but on revmob docs it is assign to button and in cocos2d i dont have Button i am using CCMenuItemImage.
Link
THis is how it works. (Official Doc)
- (void)viewDidLoad {
[super viewDidLoad];
CGFloat width = floorf(self.view.frame.size.width*.8);
CGFloat height = 80;
CGFloat offset = floorf((self.view.frame.size.width*.8 - width)/2);
UIButton *button = [[RevMobAds session] button];
button.frame = CGrectMake(offset,offset,height,width);
[self.view addSubview:button];
// Optional title change
[button setTitle:#"More Free Games" forState:UIControlStateNormal];
// Optional color changes
UIImage *background1 = [self imageWithColor:[UIColor grayColor]];
UIImage *background2 = [self imageWithColor:[UIColor lightGrayColor]];
[button setBackgroundImage:background1 forState:UIControlStateNormal];
[button setBackgroundImage:background2 forState:UIControlStateSelected];
// Optional rounded corner changes, require #import <QuartzCore/QuartzCore.h>
button.layer.cornerRadius = 5;
button.clipsToBounds = YES;
}
#end
Show free game button only if it loads add. Got this fix from revmob for iOS 6.1.3
-(id)init
{
...
...
[self addRevmobButtonAds];
return self;
}
-(void)addRevmobButtonAds
{
RevMobAdLink *ad = [[RevMobAds session] adLink];
[ad loadWithSuccessHandler:^(RevMobAdLink *link)
{
[self showFreeGameButton];
} andLoadFailHandler:^(RevMobAdLink *link, NSError *error) {
}];
}
-(void) showFreeGameButton
{
CCSprite *more_1 = [CCSprite spriteWithSpriteFrameName:#"moreGamebtn.png"];
CCSprite *more_2 = [CCSprite spriteWithSpriteFrameName:#"moreGameSelected.png"];
CCMenuItemSprite *moreBtn = [CCMenuItemSprite itemFromNormalSprite:more_1
selectedSprite:more_2
target:self
selector:#selector(moreBtnPress:) ];
moreBtn.position = ccp(mS.width*0.75f, mS.height*0.145f);
moreBtn.scale = 0.0f;
CCMenu *menu = [CCMenu menuWithItems:moreBtn, plyBtn, nil];
menu.position = ccp(0.0f,0.0f);
[self addChild:menu z:2 ];
}
-(void)moreBtnPress:(id)sender
{
[[RevMobAds session] showPopup];
[[SimpleAudioEngine sharedEngine] playEffect:#"step.wav" ];
}
You can add a UIButton to a Cocos2D scene the following way:
CGSize winSize = [[CCDirector sharedDirector] winSize];
CGFloat width = floorf(winSize.width*.8);
CGFloat height = 80;
CGFloat offset = floorf((winSize.width*.8 - width)/2);
UIButton *button = [[RevMobAds session] button];
button.frame = CGrectMake(offset,offset,height,width);
[[[CCDirector sharedDirector] view] addSubview:button];
Just note that it will exist over any and all of your Cocos2D nodes.

iOS Crossfading Multiple Images in imageviews

I have 9 images that I need to cross fade. I tried to do animation with animationImages method of imageview. But unfortunately, it does not support cross fading effect between images. Can anybody tell me how to achieve this?
I usually use Core Animation, specifically CABasicAnimation,
I used this recently, an image view with a couple of gesture recognizers for left and right swipe. Check out the fading animations I am using:
_someImageView = [[UIImageView alloc] initWithFrame:myFrame];
_someImageView.image = [myArrayOfImages objectAtIndex:0];
[self.view addSubview:_someImageView];
[_someImageView release];
_currentImageIndex = 0;
_someImageView.userInteractionEnabled = YES;
UISwipeGestureRecognizer *swipeLeftGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(changeImage:)];
swipeLeftGesture.direction = UISwipeGestureRecognizerDirectionLeft;
[_someImageView addGestureRecognizer:swipeLeftGesture];
[swipeLeftGesture release];
UISwipeGestureRecognizer *swipeRightGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(changeImage:)];
swipeRightGesture.direction = UISwipeGestureRecognizerDirectionRight;
[_someImageView addGestureRecognizer:swipeRightGesture];
[swipeRightGesture release];
Then this is called every time I swipe, or if you prefer to do something time based, then have your timer call this, just make sure you increment a counter so that you can loop the images:
- (void)changeImage:(UISwipeGestureRecognizer *)swipe{
NSArray *images = [myArrayOfImages images];
NSInteger nextImageInteger = _currentImageIndex;
if(swipe.direction == UISwipeGestureRecognizerDirectionLeft)
nextImageInteger++;
else
nextImageInteger--;
if(nextImageInteger < 0)
nextImageInteger = images.count -1;
else if(nextImageInteger > images.count - 1)
nextImageInteger = 0;
_currentImageIndex = nextImageInteger;
UIImage *target = [images objectAtIndex:_currentImageIndex];
CABasicAnimation *crossFade = [CABasicAnimation animationWithKeyPath:#"contents"];
crossFade.duration = 0.5;
crossFade.fromValue = _someImageView.image;
crossFade.toValue = target;
[_someImageView.layer addAnimation:crossFade forKey:#"animateContents"];
_someImageView.image = target;
}
Just create two image views and lay them on top of one another. When you want to crossfade to the next image, just set the bottom image view's image to the image you want to fade to, and animate the alpha of the top image view to 0. Rinse and repeat.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
UIImage *img=[UIImage imageNamed:#"images.jpeg"];
imgview=[[UIImageView alloc]init];
imgview.frame=CGRectMake(30,90, img.size.width, img.size.height);
[self.view addSubview:imgview];
[self animateImages];
}
- (void)animateImages
{
static int count = 0;
NSArray *animationImages = #[[UIImage imageNamed:#"images.jpeg"], [UIImage imageNamed:#"images (1).jpeg"]];
UIImage *image = [animationImages objectAtIndex:(count % [animationImages count])];
[UIView transitionWithView:imgview
duration:2.0f // animation duration
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
imgview.image = image;
} completion:^(BOOL finished) {
[self animateImages];
count++;
}];
}

Resources