Is there a way to animate a UIButton background image view with a set of images?
I've managed to do so with the imageView property, but couldn't find an equivalent background property.
10x
Here's what I did (inside a UIButton subclass):
Set the button images, like regular:
[self setBackgroundImage:[[UIImage imageNamed:#"button"] resizableImageWithCapInsets:UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0)] forState:UIControlStateNormal];
[self setBackgroundImage:[[UIImage imageNamed:#"button_pressed"] resizableImageWithCapInsets:UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0)] forState:UIControlStateHighlighted];
Override highlighted:
- (void)setHighlighted:(BOOL)highlighted {
[UIView transitionWithView:self duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowAnimatedContent animations:^{
[super setHighlighted:highlighted];
} completion:nil];
}
To change a buttons backround image, or text for that matter - you need to change it for the particular UIControlState... i.e Highlighted, Selected, Disabled
Use
- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state
I'm not sure if you can animate them, I've never tried. If you can't animate them, then you could put a UIImageView behind a transparent button and animate the images in that instead - just a thought.
You can animate an UIButton the way you animate an UIImageView like this...
-(void) addAnimationToButton:(UIButton*) button{
UIImageView* animationView = [button imageView];
NSArray* animations=[NSArray arrayWithObjects:
[UIImage imageNamed:#"sprite1.png"],
[UIImage imageNamed:#"sprite2.png"],
[UIImage imageNamed:#"sprite2.png"],
//and so on if you need more
nil];
CGFloat animationDuration = 2.0;
[animationView setAnimationImages:animations];
[animationView setAnimationDuration:animationDuration];
[animationView setAnimationRepeatCount:0]; //0 is infinite
}
And you use it like this:
[self addAnimationToButton:yourButton];
[[yourButton imageView] startAnimating]; //or stopAnimating
Yes it is possible. Use NSTimer ,
NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:5.00 target:self selector:#selector(changeImage) userInfo:nil repeats:YES];
then, method is as follows,
- (void)changeImage
{
static int counter = 0;
if([bannerArray count] == counter)
{
counter = 0;
}
[button setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:bannerArray[counter]]]] forState:UIControlStateNormal];
counter++;
}
It worked for me. But adding animation like flip etc need to figure out. Hope this also one way to help your need.
Related
Now i am working in iPhone application, Using UIImageView to create a animation and it's working fine, then i tried to call one method for when the animation once completed then the button to show on the screen, but that button showing first then the animation starts, i want once animation completed then the button showing on the screen, how to fix this issue? please help me
Thanks in Advance
I tried this for your reference:
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray * imageArray = [[NSArray alloc] initWithObjects:[UIImage imageNamed:#"cardopen.png"],
[UIImage imageNamed:#"middlecard.png"],
[UIImage imageNamed:#"thirdcard.png"],
[UIImage imageNamed:#"a.png"],
[UIImage imageNamed:#"cardopen1.png"],
[UIImage imageNamed:#"middlecard2.png"],
[UIImage imageNamed:#"thirdcard1.png"],
[UIImage imageNamed:#"2.png"],
nil];
UIImageView * cardsImage = [[UIImageView alloc] initWithFrame:CGRectMake(10, 0, 400, 300)];
cardsImage.animationImages = imageArray;
cardsImage.animationDuration = 8.0;
cardsImage.animationRepeatCount=1; // one time looping only
[self.view addSubview:cardsImage];
[cardsImage startAnimating];
[self method1]; // To Call a method1 to show UIButton (Once the animation is completed, then to call a method1)
}
-(void)method1
{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame=CGRectMake(10, 40, 50, 50);
[self.view addSubview:btn];
}
(Why doesn't anybody understand the concept of asynchronous methods? Is this that hard?)
[cardsImage startAnimating];
returns immediately, not after the animation finished. You have to set an explicit timeout:
NSTimer *tm = [NSTimer scheduledTimerWithTimeInteral:imageView.animationDuration * imageView.animationCount // assuming animationCount is not 0
target:self
selector:#selector(method1)
repeats:NO
userInfo:nil];
Use
[self performSelector:#selector(method1) withObject:nil afterDelay:8.0];
instead of [self method1];
This is because you are putting all of your code in ViewDidLoad. The whole method will be processed . Plus you have your animation duration set to 0.8 which is a slow animation.So the button would appear normally and the animation would continue along with it and then even more. So what you actually have to do is use an NSTimer or use the answers provided to you here :)
Here's my view hierarchy: parentView (UIView) has a UIImageView as its subview which in turn has a UIButton as its subview.
left = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"left.png"]];
left.userInteractionEnabled = YES;
[parentView addSubview:left];
back = [UIButton buttonWithType:UIButtonTypeCustom];
[back setImage:[UIImage imageNamed:#"Arrow-left.png"] forState:UIControlStateNormal];
[back addTarget:self action:#selector(back:) forControlEvents:UIControlEventTouchUpInside];
back.showsTouchWhenHighlighted = YES;
[left addSubview:back];
Everything shows up properly but the button does not respond to touches. It does respond if I move its frame out of the UIImageView's frame to somewhere else and set it as a subView to the parentView (UIView). But here's the thing.
Even if I set to parentView's subView the button does not respond if it is within the UIImageView's frame area. The userInteractionEnabled property has been already set to YES for the image view. Any idea what's going on?
UIImageView turns off userInteraction - turn it on and the button will work.
EDIT:
So I used your code almost exactly as written - the one red herring is that you said it all appears fine. For me, the custom button had a frame of 0,0,0,0 so I saw nothing. When I set the frame it all worked perfectly:
UIButton *back = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *image = [UIImage imageNamed:#"46-truck.png"];
assert(image);
[back setImage:image forState:UIControlStateNormal];
[back addTarget:self action:#selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
back.showsTouchWhenHighlighted = YES;
back.frame = (CGRect){ {0,0}, image.size};
NSLog(#"FRAME: %#", NSStringFromCGRect(back.frame) );
[imageView addSubview:back];
So, if you need to probe the superviews during run time to figure out what is what, you can use this code below. [UIView dumpSuperviews:back msg:#"Darn Bark Button"];
#interface UIView (Utilities_Private)
+ (void)appendView:(UIView *)v toStr:(NSMutableString *)str;
#end
#implementation UIView (Utilities_Private)
+ (void)appendView:(UIView *)a toStr:(NSMutableString *)str
{
[str appendFormat:#" %#: frame=%# bounds=%# layerFrame=%# tag=%d userInteraction=%d alpha=%f hidden=%d\n",
NSStringFromClass([a class]),
NSStringFromCGRect(a.frame),
NSStringFromCGRect(a.bounds),
NSStringFromCGRect(a.layer.frame),
a.tag,
a.userInteractionEnabled,
a.alpha,
a.isHidden
];
}
#end
#implementation UIView (Utilities)
+ (void)dumpSuperviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
while(v) {
[self appendView:v toStr:str];
v = v.superview;
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
+ (void)dumpSubviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
if(v) [self appendView:v toStr:str];
for(UIView *a in v.subviews) {
[self appendView:a toStr:str];
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
#end
Maybe
parentView.userInteractionEnabled = YES;
Or parent view frame are to small and can`t hold button or image view. Check size of parent view;
I've had this happen before.. I think it was a super view swallowing the event.
I know you've stated that adding it to the parentView only works if it doesn't overlap with the image view. If you disable user interaction on the image view, does the button event trigger consistently when added to the parentView?
You actually need to set userInteractionEnabled = NO to allow the touches to pass through.
Taken from here.
left.userInteractionEnabled = YES;
put this line in the end.
How can I remove the gloss/shine effect from the buttons on navigation bars?
If I customize the navigation bar by using a custom image the buttons are not affected, can I remove the effect from them (the line and glossing), or define a hex color code for the whole button, or even a custom image for them too?
I just went through the process of figuring this out. Basically, you need to create custom stretchable images and use them as the button's background to get rid of the shine. Replacing the back buttons in a UINavigationController is a bit tougher. For that I used a UINavigationControllerDelegate to replace the default back button with my custom button.
Here's some code:
Create a category on UIBarButtonItem that creates your custom button. Here's mine. I use this category to customize both regular bar buttons and back buttons:
#interface UIBarButtonItem (UIBarButtonItem_customBackground)
+ (id) customBarButtonWithTitle:(NSString *)title target:(id)target selector:(SEL)selector;
+ (id) customBackButtonWithTitle:(NSString *)title target:(id)target selector:(SEL)selector;
#end
#implementation UIBarButtonItem (UIBarButtonItem_customBackground)
+ (id) customButtonWithImageNamed:(NSString *)imageName selectedImageNamed:(NSString *)selectedImageName leftCapWidth:(CGFloat)leftCapWidth edgeInsets:(UIEdgeInsets)edgeInsets title:(NSString *)title target:(id)target selector:(SEL)selector {
UIButton* customButton = [UIButton buttonWithType:UIButtonTypeCustom];
[customButton addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside];
customButton.titleLabel.font = [UIFont boldSystemFontOfSize:12.0f];
customButton.titleLabel.shadowColor = [UIColor colorWithRed:0.0f/255.0f green:0.0f/255.0f blue:0.0f/255.0f alpha:0.25f];
customButton.titleLabel.shadowOffset = CGSizeMake(0.0f, -1.0f);
customButton.titleLabel.lineBreakMode = UILineBreakModeTailTruncation;
customButton.titleEdgeInsets = edgeInsets;
UIImage* navButtonBackgroundImage = [[UIImage imageNamed:imageName] stretchableImageWithLeftCapWidth:leftCapWidth topCapHeight:0.0f];
UIImage* navButtonPressedBackgroundImage = [[UIImage imageNamed:selectedImageName] stretchableImageWithLeftCapWidth:leftCapWidth topCapHeight:0.0f];
[customButton setBackgroundImage:navButtonBackgroundImage forState:UIControlStateNormal];
[customButton setTitle:title forState:UIControlStateNormal];
[customButton setBackgroundImage:navButtonPressedBackgroundImage forState:UIControlStateHighlighted];
[customButton setBackgroundImage:navButtonPressedBackgroundImage forState:UIControlStateSelected];
CGSize size = CGSizeMake(30.0f, 30.0f);
if (title != nil) {
size = [[NSString stringWithString:title] sizeWithFont:customButton.titleLabel.font];
}
customButton.frame = CGRectMake(0.0f, 0.0f, size.width + 20.0f, 30.0f);
customButton.layer.shouldRasterize = YES;
customButton.layer.rasterizationScale = [[UIScreen mainScreen] scale];
return [[[UIBarButtonItem alloc] initWithCustomView:customButton] autorelease];
}
+ (id) customBarButtonWithTitle:(NSString *)title target:(id)target selector:(SEL)selector {
return [self customButtonWithImageNamed:#"navButtonBG.png"
selectedImageNamed:#"navButtonPressedBG.png"
leftCapWidth:6.0f
edgeInsets:UIEdgeInsetsMake(0.0f, 5.0f, 0.0f, 5.0f)
title:title
target:target
selector:selector];
}
+ (id) customBackButtonWithTitle:(NSString *)title target:(id)target selector:(SEL)selector {
return [self customButtonWithImageNamed:#"backButtonBG.png"
selectedImageNamed:#"backButtonPressedBG.png"
leftCapWidth:12.0f
edgeInsets:UIEdgeInsetsMake(0.0f, 11.0f, 0.0f, 5.0f)
title:title
target:target
selector:selector];
}
#end
Add the button to your UINavigationBar
UIBarButtonItem* logoutButton = [UIBarButtonItem customBarButtonWithTitle:#"Logout" target:self selector:#selector(logout)];
self.navigationItem.rightBarButtonItem = logoutButton;
If you also want to replace the UINavigationController's back buttons, setup a UINavigationControllerDelegate and implement the willShowViewController method like so:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if([navigationController.viewControllers count ] > 1) {
UIViewController* backViewController = [navigationController.viewControllers objectAtIndex:(navigationController.viewControllers.count - 2)];
NSString* backText = backViewController.title;
UIBarButtonItem* newBackButton = [UIBarButtonItem customBackButtonWithTitle:backText target:navigationController selector:#selector(popViewControllerAnimated:)];
viewController.navigationItem.leftBarButtonItem = newBackButton;
viewController.navigationItem.hidesBackButton = YES;
}
}
Here are the stretchable images I'm using:
Back button: Pressed:
Regular button: Pressed:
For changing the back button it is not necessary to implement the delegate method uinavigationcontroller.
You only need set the hidesBAckButton property to YES after setting the desired backbutton as #Justin Gallacher explained perfectly.
self.navigationItem.leftBarButtonItem = [UIBarButtonItem customBackButtonWithTitle:#"Back" target:self.navigationController selector:#selector(popViewControllerAnimated:)];
self.navigationItem.hidesBackButton = YES;
you have to use the custom button with images without any gloss effect on the images by which you can get rid of the gloos effect of the button from navbar.
I have a UILabel and when the value change in the label, I want to highlight it's background color from another color and exists for 2,3 seconds and get back to normal color.
Anyone have an idea how to do this?
Add quartzCore as a framework
Add an import QuartzCore/QuartzCore.h
Use this code
- (void) initController
{
UIButton *myButton = [view viewWithTag:1]; // Just reference the button you have
[myButton addTarget:self action:#selector(animateLabel) forControlEvents:UIControlEventTouchUpInside];
}
- (void) animateLabel
{
CABasicAnimation* highlightAnim = [CABasicAnimation animationWithKeyPath:#"backgroundColor"];
highlightAnim.toValue = (id)[UIColor blueColor].CGColor;
highlightAnim.duration = 2; // In seconds
highlightAnim.autoreverses = YES; // If you want to it to return to the normal color
[label.layer addAnimation:highlightAnim forKey:nil];
}
What I Want: A border indicating if a UIButton is selected or not.
Background: I've got some UIButtons using transparent images, not text. These are toggle buttons (i.e. can be on or off).
Problem: The UIButton class gives users no indication of whether a button is selected or not unless you change something else about the button. Since the image doesn't change with the state, I'd need two of every image, one normal, one selected and set one for each state of the button. This is annoying. I thought instead I'd change the background image, but this removes the pretty border on the button, I just get a rectangle of my background image, yuck.
Possible solutions I don't like:
1) Create a background that matches the UIButton border and use that for selected. I don't like this because they wont match perfectly and I'm picky.
2) Create two images for each button, essentially identical but with a different background. This seems like unnecessary work, and since this problem is coming up repeatedly, I want a solution for the future as well.
I hope somebody's figured out a decent solution to this by now. Thanks in advance.
Since UIButton has two image layers, an image and a background image, I think you could accomplish what you want by using just two background images for all your buttons. One image shows a border and the other does not. Swap the backgrounds out when the control state changed.
//
// TabBarSingleton.h
#import <Foundation/Foundation.h>
#interface TabBarSingleton : UITabBarController <UITabBarControllerDelegate>{
NSRecursiveLock *barLock;
UIButton *Button;
UIButton *favoriteButton;
}
#property(nonatomic, retain) UIButton *Button;
#property(nonatomic, retain) UIButton *favoriteButton;
- (void) ButtonPressed;
- (void) favoriteButtonPressed;
#end
///////////////////////////////////
If you want the the borders only, then you have only one choice of using two images for the two states otherwise if your purpose is to differentiate between two states then you can do it by changing alpha a little bit of the selected button this will give the effect like toggle buttons, you can also disable the selected button and enable it again when the other button is pressed.
Hope this will give you a fair idea.
//
// TabBarSingleton.m
// Created by ArunDhwaj on 9/7/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import "TabBarSingleton.h"
#implementation TabBarSingleton
#synthesize Button, favoriteButton;
- (id) init
{
if (self = [super initWithNibName: nil bundle: nil])
{
barLock = [[NSRecursiveLock alloc] init];
}
self.delegate = self;
return self;
}
+ (TabBarSingleton *) defaultBar
{
}
- (void)viewDidLoad
{
NSLog(#"TabBarSingleton: viewDidLoad");
//Hiding TabBar
self.tabBar.hidden = YES;
//Creating a UIView, its frame is same as tabBar frme
CGRect tabbarFrame = self.tabBar.frame;
UIView* customTabbarView = [[UIView alloc] initWithFrame:tabbarFrame];
UIImageView *newsFeedImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"newsfeeds_normal.png"]];
newsFeedImg.frame = CGRectOffset(newsFeedImg.frame, 0, 1);
Button = [UIButton buttonWithType:UIButtonTypeCustom];
[Button setFrame:newsFeedImg.frame];
[Button setBackgroundImage:newsFeedImg.image forState:UIControlStateNormal];
[Button setBackgroundImage:[UIImage imageNamed:#"newsfeeds_active.png"] forState:UIControlStateHighlighted];
[Button addTarget:self action:#selector(newsFeedsButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[customTabbarView addSubview:Button];
//[newsFeedImg release];
CGRect newsFeedFrame = newsFeedImg.frame;
UIImageView *favoriteImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"favorites_normal.png"]];
favoriteImg.frame = CGRectMake(newsFeedFrame.size.width, newsFeedFrame.origin.y, newsFeedFrame.size.width, newsFeedFrame.size.height);
favoriteButton = [UIButton buttonWithType:UIButtonTypeCustom];
[favoriteButton setFrame:favoriteImg.frame];
[favoriteButton setBackgroundImage:favoriteImg.image forState:UIControlStateNormal];
[favoriteButton setBackgroundImage:[UIImage imageNamed:#"favorites_active.png"] forState:UIControlStateHighlighted];
[favoriteButton addTarget:self action:#selector(favoriteButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[customTabbarView addSubview: favoriteButton];
//[favoriteImg release];
[self.view addSubview:customTabbarView ];
[self newsFeedsButtonPressed];
}
- (void) newsFeedsButtonPressed
{
NSLog(#"TabBarSingleton: newsFeedsButtonPressed");
self.selectedIndex = 0;
//Keeping Highlighted newsFeed tab
UIImageView *newsFeedImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"newsfeeds_active.png"]];
[Button setImage: newsFeedImg.image forState:UIControlStateNormal];
//Keeping normal others tab icons
UIImageView *favoriteImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"favorites_normal.png"]];
[favoriteButton setImage: favoriteImg.image forState:UIControlStateNormal];
}
- (void) favoriteButtonPressed
{
NSLog(#"TabBarSingleton: favoriteButtonPressed");
self.selectedIndex = 1;
//Keeping Highlighted newsFeed tab
UIImageView *newsFeedImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"newsfeeds_normal.png"]];
[Button setImage: newsFeedImg.image forState:UIControlStateNormal];
//Keeping normal others tab icons
UIImageView *favoriteImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"favorites_active.png"]];
[favoriteButton setImage: favoriteImg.image forState:UIControlStateNormal];
#pragma mark UITabBarControllerDelegate
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
NSLog(#"TabBarSingleton: shouldSelectViewController");
return YES;
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
NSLog(#"TabBarSingleton: didSelectViewController");
}
- (void) dealloc
{
//[barLock release];
[super dealloc];
}
#end