Is there an easy way to have an on state and an off state for the UIBarButtonItems, with different images for each?
Thanks
There isn't a built-in way, but I can think of a few approaches (depending on your needs):
Bind the button to a method that toggles whatever the button is meant to toggle, and then changes the button's image property accordingly
Create your own subclass of UIBarButtonItem that looks something like this:
#interface ToggleBarButtonItem : UIBarButtonItem {
BOOL _state;
UIImage * onImage;
UIImage * offImage;
}
- (BOOL)toggleState;
#property (nonatomic, retain) UIImage * onImage;
#property (nonatomic, retain) UIImage * offImage;
#end
#implementation ToggleBarButtonItem
- (BOOL)toggleState {
if (_state) {
// Switch to Off state
self.image = offImage;
}
else {
// Switch to On state
self.image = onImage;
}
return _state = !_state;
}
#end
Related
I would like the NavigationBar to behave the same but would like to change the appearance of it. I've found so many ways of doing this online but I'm not sure which one is the best result for iOS 5.0. The navigation bar will look like this:
Since you are targeting iOS 5 i would definitely go for customizing UINavigationBar using the Appearance proxy. Then you can easily set your own images and they will apply to all navigation bars in your application without subclassing.
You can also customize the buttons in the navigation bar by customizing UIBarButtonItem. There are method like backButtonBackgroundImageForState:barMetrics: for the back button and backgroundImageForState:barMetrics: for the other buttons.
I had been looking for this thing for ages, too, without finding a straightforward solution! Thanks to an friend of mine, and sample codes, we made it with a custom navigation bar class that can be imported into any view controller class.
The .h file:
#import <UIKit/UIKit.h>
#interface NATitleBar : UIView {
NSInteger tag;
}
#property ( nonatomic) IBOutlet UIImageView *imageView;
#property ( nonatomic) IBOutlet UILabel *label;
#property ( nonatomic) IBOutlet UIButton *back;
#property ( nonatomic) IBOutlet UIButton *home;
/**
* Supports UIButton-style adding targets
*/
#end
The .m file:
#import "NATitleBar.h"
#implementation NATitleBar
#synthesize imageView;
#synthesize label;
#synthesize back;
#synthesize home;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
NSArray *views = [[NSBundle mainBundle] loadNibNamed:#"NATitleBar" owner:self options:nil];
[self addSubview:[views objectAtIndex:0]];
// customize the view a bit
//self.imageView.layer.borderWidth = 1.0;
//self.imageView.layer.borderColor = [UIColor colorWithWhite:0.4 alpha:0.4].CGColor;
//self.imageView.clipsToBounds = YES;
//self.imageView.layer.cornerRadius = 5.0;
}
return self;
}
#pragma mark - Overriden Setters / Getters
- (void)setTag:(NSInteger)aTag {
self.back.tag = aTag;
}
- (NSInteger)tag {
return self.back.tag;
}
#end
and then for the Nib file we have the following:
You can add or delete images in the Nib file to make the GUI as you wish.
Now you must import the class into any view controller you wish to have with custom navigation controller, and also define two methods (or one, if you don't want the 'home' button. in .h :
- (void) back;
in .m:
- (void)back {
[self.navigationController popViewControllerAnimated:YES];
}
I added 6 UIImageViews in Interface Builder.
Those are declared.
#property (nonatomic, strong) IBOutlet UIImageView *Image1;
#property (nonatomic, strong) IBOutlet UIImageView *Image2;
#property (nonatomic, strong) IBOutlet UIImageView *Image3;
#property (nonatomic, strong) IBOutlet UIImageView *Image4;
#property (nonatomic, strong) IBOutlet UIImageView *Image5;
#property (nonatomic, strong) IBOutlet UIImageView *Image6;
Those UIImageView' name has a rule - "Image" + number.
I want to select those ImageViews dinamically.
For example,
for (NSInteger i = 0; i < 6 ; i++) {
if(... condition )
{
//new
[[NSString stringWithFormat:#"Image%d", i+1] setHidden:YES]; //--(1)
}
else
{
[[NSString stringWithFormat:#"Image%d", i+1] setHidden:NO]; //--(2)
}
}
But, this code isn't correct.
Please tell me more good way.
jonkroll's suggestion to put your image views in an array is a good way to do it, and generally the highest performance.
Another way is to use key-value coding (KVC) to access your properties by name:
for (int i = 0; i < 6; ++i) {
NSString *key = [NSString stringWithFormat:#"Image%d", i + 1];
UIImageView *imageView = (UIImageView *)[self valueForKey:key];
imageView.hidden = condition;
}
Using the view tag, as Mark suggests, is a third way to do it. His answer is a little short on details, so I will provide some.
You can set the tag in your nib:
So you can set the tag of your Image1 image view to 1, and the tag of your Image2 image view to 2, and so on.
Then you can find an image view by its tag using the viewWithTag: method on your top-level view:
for (int i = 0; i < 6; ++i) {
[self.view viewWithTag:i+1].hidden = condition;
}
Create an array of your imageViews and iterate over them using fast enumeration:
NSArray *imageViewArray = [NSArray arrayWithObjects:self.Image1,self.Image2,self.Image3,self.Image4,self.Image5,self.Image6,nil];
for (UIImageView* imageView in imageViewArray) {
if(... condition ) {
[imageView setHidden:YES]; //--(1)
} else {
[imageView setHidden:NO]; //--(2)
}
}
typically you can use Tag to identify your views, instead of using the name of the view.
#property(nonatomic) NSInteger tag
see here:
https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIView_Class/UIView/UIView.html
once you've set the tag, you can then do things like
if(uiview.tag == kSomeButtonTag)
Is it possible to change the width of UITabbarItem in UITabbar and margins between each UITabbarItem for iPad Application?
The problem is that standard margins are too large for my layout - client want tabs to be more compact :/
Or should I mess with UIToolbar to achieve this goal?
For Tabbar item width :
[[UITabBar appearance] setItemWidth:self.window.frame.size.width/NUMBER_OF_ITEMS];
For tabbar frame :
[self.tabBar setFrame:rectFrame];
I have solved just the same problem it this way:
my goal was to customize tab bar by using images, that were sent by the designer for me.
I have attached the .png files for the project, initialized the correspondent variables of type UIImage* and used UITabBarItem function setFinishedSelectedImage: withFinishedUnselectedImage: to set the images for active / inactive state of UITabbarItem:
UIImage * left_active, *left_inactive, *center_active, *center_inactive, *right_active, *right_inactive;
left_active = [UIImage imageNamed:#"left_active_img"];
...
[self.leftTabBarItem setFinishedSelectedImage:left_active withFinishedUnselectedImage:left_inactive];
[self.centerTabBarItem setFinishedSelectedImage:center_active withFinishedUnselectedImage:center_inactive];
[self.rightTabBarItem setFinishedSelectedImage:right_active withFinishedUnselectedImage:right_inactive];
But the customized tabbarItems were smaller, than the designer's images and were allocated at the center of the screen one upon other:
2) To fix this I have ADDED ADDITIONAL UITABBARITEMS - at the left and at the right corner of the initial ones
3) the were created the correspondent outlets for the UITabBarItems:
.h-file:
#property (nonatomic, retain) IBOutlet UITabBar * tabBar;
// THE INTIAL items
#property (nonatomic, retain) IBOutlet UITabBarItem * leftTabBarItem;
#property (nonatomic, retain) IBOutlet UITabBarItem * centerTabBarItem;
#property (nonatomic, retain) IBOutlet UITabBarItem * rightTabBarItem;
// THE ADDITIONAL items
#property (nonatomic, retain) IBOutlet UITabBarItem * left_1;
#property (nonatomic, retain) IBOutlet UITabBarItem * left_2;
#property (nonatomic, retain) IBOutlet UITabBarItem * center_1;
#property (nonatomic, retain) IBOutlet UITabBarItem * center_2;
#property (nonatomic, retain) IBOutlet UITabBarItem * right_1;
#property (nonatomic, retain) IBOutlet UITabBarItem * right_2;
then attached the Outlets to the UITabBarItems in the order listed below:
left_1
leftTabBarItem
left_2
center_1
centerTabBarItem
center_2
right_1
rightTabBarItem
right_2
and CORRECTED THE UITabbarDelegate METHOD in the delegating class to switch ONLY beet wen the visible items
.m-file:
#pragma mark - UITabbarDelegate
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item{
if (item == self.leftTabBarItem)
{
NSLog(#"0"); // first visible item selected
} else if (item == self.centerTabBarItem)
{
NSLog(#"1"); // second visible item selected
} else if (item == self.rightTabBarItem)
{
NSLog(#"2"); // third visible item selected
} else if (item == self.left_1){
[self.tabBar setSelectedItem: self.leftTabBarItem];
} else if (item == self.left_2){
[self.tabBar setSelectedItem: self.leftTabBarItem];
} else if (item == self.center_1){
[self.tabBar setSelectedItem: self.centerTabBarItem];
}else if (item == self.center_2){
[self.tabBar setSelectedItem: self.centerTabBarItem];
}else if (item == self.right_1){
[self.tabBar setSelectedItem: self.rightTabBarItem];
} else if (item == self.right_2){
[self.tabBar setSelectedItem: self.rightTabBarItem];
}
}
Now everything looks and works properly.
You can use the same steps to customize the size and interspaces between UITabBarItems by adding additional items and correcting delegate methods.
I don't think it is possible. You can create a custom tab bar. Also messing around with default UItabbar might cause rejection during App approval process.
You can change the spacing of the tab bar items by subclassing UITabBar and overriding its layoutSubviews method. You will find all tab bar buttons in the self.subViews array. Their class is the non-public UITabBarButton but they inherit from UIControl so you can identify all tab bar buttons checking if they are kind of UIControl class. Then all you need is to change the frame of the tab bar buttons.
You can use setSelectionIndicatorImage to make your tab more compact.
The UITabBarItem width in iPad will match the selectionIndicatorImage's width
in AppDelegate.m
[[UITabBar appearance] setItemWidth:self.window.frame.size.width/NUMBER_OF_YOUR_TAB];
[[UITabBar appearance] setItemSpacing:0];
[[UITabBar appearance] setSelectionIndicatorImage:[self imageFromColor:[UIColor clearColor] forSize:CGSizeMake(self.window.frame.size.width/NUMBER_OF_YOUR_TAB, 10) withCornerRadius:0]];
you can use below code to create a image programmatically
- (UIImage *)imageFromColor:(UIColor *)color forSize:(CGSize)size withCornerRadius:(CGFloat)radius
{
CGRect rect = CGRectMake(0, 0, size.width, size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIGraphicsBeginImageContext(size);
[[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius] addClip];
// Draw your image
[image drawInRect:rect];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
No subclassing is needed.
tabBarController.tabBar.itemPositioning = .centered
tabBarController.tabBar.itemWidth = 40
tabBarController.tabBar.itemSpacing = 38
You cannot change the width of the the UITabBarItem, and you cannot do this even after subclassing the UITabBarItem. Apple has certain restrictions in the way they want the developers to implement the applications.
You will need to use a UIToolBar for this, and my best bet is for you to go to github and as there a lot of sample applications which use a scrollable UIToolBar at the bottom instead of the UITabBar.
I am new to iphone and xcode. This may be a very simple question but I could not find an example code in books. I want to do the following:
Have 2 UIView on the screen
Each view will step through the color of the rainbow (red/orange/yellow/green/blue/indigo/violet) using gesture recognizer, e.g., if the current color is green, if the user swipes up the UIView changes to yellow, if the user swipes down the UIView changes to blue.
Hence, each view will need to keep the current color and respond to the swipes accordingly.
I understand how to implement the detection of swipes using gesture recognizer but I don't know how to have each view keep a separate variable for the current color. I want a generic code because there will be more than 2 UIViews in my application once I figure out how it is done.
Thanks in advance.
You can subclass UIView to include any variables that you like:
ColorSwiperView.h
#interface ColorSwiperView : UIView
{
ColorType currentColor;
}
#property (nonatomic, assign) ColorType currentColor;
#end
ColorSwiperView.m
#implementation ColorSwiperView
#synthesize currentColor;
- (id)initWithFrame:(CGRect)frameRect
{
if ((self = [super initWithFrame:frameRect]) == nil) { return nil; }
currentColor = red;
return self;
}
#end
To be used as follows:
#import "ColorSwiperView"
...
ColorSwiperView * cView = [[ColorSwiperView alloc] initWithFrame:...];
cView.currentColor = green;
Note: this assumes that you have defined an enum for the colors:
typedef enum
{
red = 0,
green = 1,
...
}
ColorType;
perhaps defining a subclass of UIView something like:
#interface RainbowView : UIView {
UIColor *currentColor;
}
#property (nonatomic, retain) UIColor *currentColor;
#end
and creating 2 (or more) views of that class in your view controller as outlets (if you're using interface builder):
#class RainbowView;
#interface RainBowViewController : UIViewController {
RainbowView *rainbowView1;
RainbowView *rainbowView2;
}
#property (nonatomic, retain) IBOutlet RainbowView *rainbowView1;
#property (nonatomic, retain) IBOutlet RainbowView *rainbowView2;
#end
Since you are going to maintain an array of colors, say colorsArray, and assign views their color from that selection. You can do this in the swipe handler.
- (void)handleSwipe:(UISwipeGestureRecognizer*)swipeGesture {
UIView *view = swipeGesture.view;
NSInteger currentColorIndex = [colorsArray indexOfObject:view.backgroundColor];
NSInteger nextColorIndex = currentColorIndex + 1;
if ( nextColorIndex == [colorsArray count] ) {
nextColorIndex = 0;
}
view.backgroundColor = [colorsArray objectAtIndex:nextColorIndex];
}
This way you don't need to subclass.
Subclassing
You can subclass UIView and add your own instance variables to it. Say,
#interface RainbowView: UIView {
NSInteger currentColorIndex;
}
#property (nonatomic, assign) NSInteger currentColorIndex;
...
#end
#implementation RainbowView
#synthesize currentColorIndex;
...
#end
In your gesture handling method,
- (void)handleSwipe:(UISwipeGestureRecognizer*)swipeGesture {
RainbowView *aView = (RainbowView*)swipeGesture.view;
// Get the next color index to aView.currentColorIndex;
aView.backgroundColor = [colorsArray objectAtIndex:nextColorIndex];
aView.currentColorIndex = nextColorIndex;
}
I have a view with a subview whose alpha and backgroundcolor I would like to change through the use of declared properties. I have written some code as below and it works fine to change the alpha, but the background color is not changed when the property is set to a new value. Any help would be appreciated please.
#interface MyView : UIView {
float viewAlpha;
UIColor *viewColor;
}
#property (nonatomic, assign, readwrite) float viewAlpha;
#property (nonatomic, retain, readwrite) UIColor *viewColor;
#implementation MyView
#synthesize viewAlpha, viewColor;
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.viewAlpha = 1.0;
self.viewColor = [UIColor whiteColor];
UIView *infoView = [[UIView alloc] initWithFrame:CGRectMake(0,0,50,50)];
infoView.alpha = self.viewAlpha;
infoView.backgroundColor = self.viewColor;
[self addSubview:infoView];
[infoView release];
}
return self;
}
You might need to write a custom setter and flag that your view needs to redraw when it changes. It'd be a good idea to do this for both the alpha and the color.