iOS App view and navigation design custom class - iphone

In my iOS App I have the below code snipped repeating over and over again in every class.
I have tried to cast the method into a NSObject class but I receive errors for the use of "navigationItem".
-(void)customDesign {
//background pattern
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"BG-pattern.png"]];
// nav bar
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"top_bar.png"] forBarMetrics:UIBarMetricsDefault];
//back button color #2974c3
[self.navigationController.navigationBar setTintColor:[UIColor colorWithRed:41.0/255.0f green:116.0/255.0f blue:195.0/255.0f alpha:1.0]];
//settings button
UIImage* settingsImage = [UIImage imageNamed:#"ButtonMenu.png"];
CGRect frameimg = CGRectMake(0, 0, settingsImage.size.width, settingsImage.size.height);
UIButton *uiSettingsButton = [[UIButton alloc] initWithFrame:frameimg];
[uiSettingsButton setBackgroundImage:settingsImage forState:UIControlStateNormal];
[uiSettingsButton addTarget:self action:#selector(menuButton) forControlEvents:UIControlEventTouchUpInside];
[uiSettingsButton setShowsTouchWhenHighlighted:YES];
//add buton to navbar
UIBarButtonItem *settingsButton = [[UIBarButtonItem alloc] initWithCustomView:uiSettingsButton];
self.navigationItem.leftBarButtonItem = settingsButton;
}

You should be creating your own subclass of UIViewController or UITableViewController (whichever you're using) and place this code in your viewDidLoad method of that subclass. All the controllers that need this code can then extend your custom class. This will save you the hassle of having to write this code everywhere.
Your custom subclass:
#interface CustomViewController : UIViewController
#end
Your viewDidLoad method in the subclass:
#implementation CustomViewController
- (void)viewDidLoad {
[super viewDidLoad];
// all your custom code here...
}
#end
Extend your custom class for controllers you want to have common stuff done in:
#interface VisuallyChangedViewController : CustomViewController
#end
#implementation VisuallyChangedViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
#end

Related

Prevent custom UINavigationBar elements from changing between views

Simple question: in the main view controller of my app (which is in a navigation controller), I am customizing the nav bar with something like this:
self.navigationItem.titleView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"titleImage"]];
UIButton *menuButton = [[UIButton alloc] init];
[menuButton setImage:[UIImage imageNamed:#"menuIcon"] forState:UIControlStateNormal];
[menuButton setFrame:CGRectMake(0, 0, 34, 34)];
UIBarButtonItem *menuItem = [[UIBarButtonItem alloc] initWithCustomView:menuButton];
self.navigationItem.rightBarButtonItem = menuItem;
I want these elements - the title view and the right bar button - to remain consistent throughout the app as I push and pop new view controllers onto and off of my navigation controller.
Of course, I could just set my custom items up in viewDidLoad of every view controller that is pushed onto my navigation stack, but this means that during the animation between two view controllers, my custom items are animated in and out, which is not as clean as I would like.
Any suggestions on how I would go about maintaining those custom elements on my nav bar when switching from vc to vc? Thanks!
You could create your own navigation item class that subclasses UIButton and set all the appearance in that class, then just set your navigation items as those custom UIButtons.
Something like this:
In CustomButton.h
#import <UIKit/UIKit.h>
#interface CustomButton : UIButton
#end
Then in CustomButton.m
#implementation CustomButton
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//Set images etc.
[menuButton setImage:[UIImage imageNamed:#"menuIcon"] forState:UIControlStateNormal];
[menuButton setFrame:CGRectMake(0, 0, 34, 34)];
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
Then in your viewController:
#import CustomButton.h
- (void)viewDidLoad
{
CustomButton *button = [[CustomButton alloc]init];
self.navigationItem.leftBarButton = [[UIBarButtonItem alloc] initWithCustomView:button];
}

how to call global function from another global function with one parameter in iphone?

HiI am very new to iphone development.I am java background developer.So my approach is like java .
Here my requirement is that i want to call one global function from every view controller.
and from there i pass self.navigationController as a parameter. In that function i add some buton. when user click on that button it should call one more function and it should carry same object as a parameter.
please give me guidance. i tried as following but it is showing error at compiletime
Utilities.m
+(void)setBacKButton:(UINavigationController *)navigationController
{
for(UIButton *btn in navigationController.navigationBar.subviews){
if([btn isKindOfClass:[UIButton class]]){
[btn removeFromSuperview];
}
}
UIButton *btn2=[UIButton buttonWithType:UIButtonTypeCustom];
btn2.frame=CGRectMake(708, 0, 50, 54);
[btn2 setImage:[UIImage imageNamed:#"btn_back.png"] forState:0];
[btn2 setImage:[UIImage imageNamed:#"btn_back_h.png"] forState:UIControlStateSelected];
// here i need to call bellow function when click on this button
//[btn2 addTarget:self action:#selector() forControlEvents:UIControlEventTouchUpInside];
[navigationController.navigationBar addSubview:btn2];
}
+(void)gotoBack:(UINavigationController *)navigationController
{
[navigationController popViewControllerAnimated:YES];
}
and i call that function from my viewcontroller as
[Utilities setBacKButton:self.navigationController];
please tell me how we can achieve this
add a function in your app delegate.and call that function in all your view controllers.with an object of appdelegate.then with in that function add one button with id sender and do watever u want in the method.
Just make a navigation controller in your app Delegate ... and push your view controller using this.. follow the following code...
//YourAppdelegate.h
UINavigationController *navController;
#property(nonatomic,retain)UINavigationController *navController;
// your appdelegate.m
navController = [UINavigationController alloc]initWithRootViewController:self.viewController];
self.window.rootViewController = navController ;
and now make your global function here (in appdelegate.m) like.......
- (void)setBacKButton:(UINavigationController *)navigationController{
// put your code here
}
now call it from your view controllers where you have needed like this...
// yourViewController.m
import "yourAppdelegate.h"
and when you have to call that function just write these two lines..
YourAppdelegate *appdelegate = (YourAppdelegate*)[[UIApplication sharedApplication]delegate];
[appdelegate setBacKButton:self.navigationController];
may this will help you
you would want to create a category of UINavigationBar.
UINavigationBar+customBackButton.h
#import <UIKit/UIKit.h>
#interface UINavigationBar (customBackButton)
- (void)setCustomBackButton;
#end
UINavigationBar+customBackButton.m
#import "UINavigationBar+customBackButton.h"
#implementation UINavigationBar (customBackButton)
- (void)setCustomBackButton
{
for(UIButton *btn in self.subviews)
{
if([btn isKindOfClass:[UIButton class]])
{
[btn removeFromSuperview];
}
}
UIButton *btn2=[UIButton buttonWithType:UIButtonTypeCustom];
btn2.frame=CGRectMake(708, 0, 50, 54);
[btn2 setImage:[UIImage imageNamed:#"btn_back.png"] forState:0];
[btn2 setImage:[UIImage imageNamed:#"btn_back_h.png"] forState:UIControlStateSelected];
// here i need to call bellow function when click on this button
//[btn2 addTarget:self action:#selector() forControlEvents:UIControlEventTouchUpInside];
[self addSubview:btn2];
}
#end
Then in any view controller you can import it like this
#import "UINavigationBar+customBackButton.h"
[self.navigationController.navigationBar setCustomBackButton];
Following the response from #ewiinnnnn above, I came up with a way to use Custom Categories and have the back button navigate as expected:
// UIViewController+customBackButton.h
#import <UIKit/UIKit.h>
#interface UIViewController (customBackButton)
- (void)setCustomBackButton;
#end
// UIViewController+customBackButton.m
#import "UIViewController+customBackButton.h"
#implementation UIViewController (customBackButton)
// sets my custom back button
- (void)setCustomBackButton
{
UINavigationItem *navItem = self.navigationItem;
UIButton *customButton = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *addButton = [UIImage imageNamed:#"backButton.png"];
UIImage *addButtonSelected = [UIImage imageNamed:#"backButtonHighlighted.png"];
[customButton setBackgroundImage:addButton forState:UIControlStateNormal];
[customButton setBackgroundImage:addButtonSelected forState:UIControlStateHighlighted];
customButton.frame=CGRectMake(0.0, 0.0, addButton.size.width, addButton.size.height);
[customButton addTarget:self action:#selector(navigateBack) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView: customButton];
navItem.leftBarButtonItem = barButtonItem;
}
// the action that is triggered when the back button is pressed
- (void)navigateBack {
[self.navigationController popViewControllerAnimated:YES];
}
#end
And then within a UIViewController:
// MyViewController.m
#import "UIViewController+customBackButton.h"
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// add back button to navcontroller
[self setCustomBackButton];
}

Switching custom views programmatically (pushing and popping)

In iOS, my views work individually but I can't switch between them.
Now after a lot of google-ing around I've fond that the navigation based app would work great with the stack for views. The problem is all my views are nib/xib-less and custom tailored in the source code. Because of that I need my own UINavigationController and push and pop views by hand/code. Since every tutorial is either nib/xib and IB bound or just a mash of code snippets I need a concrete example how to do it.
A simple example with 2 programmatically created view (can be empty just have to use loadView instead of initializing with a nib/xib) and a working stack (a push and a pop of the views like: load app,create some root view if needed, push one view and from that view push the second one and then pop them) would be awesome, or at least a tutorial in that way with the whole source of the project and not snippets.
Thanks in advance.
EDIT: After some extra thinking, a little more clarification wouldn't be bad. My app will basically consist of 5 or 6 views which will be called form their respective previous view, i.e. a drill-down app.
Here's a brief code, only the essential parts:
CodeViewsPushingAppDelegate.m
#import "CodeViewsPushingAppDelegate.h"
#import "ViewNumberOne.h"
#implementation CodeViewsPushingAppDelegate
#synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
UINavigationController *navController = [[UINavigationController alloc] init];
ViewNumberOne *view1 = [[ViewNumberOne alloc] init];
[navController pushViewController:view1 animated:NO];
[self.window addSubview:navController.view];
[self.window makeKeyAndVisible];
return YES;
}
ViewNumberOne.h
#import <UIKit/UIKit.h>
#interface ViewNumberOne : UIViewController
{
UIButton *button;
}
- (void)pushAnotherView;
#end
ViewNumberOne.m
#import "ViewNumberOne.h"
#import "ViewNumberTwo.h"
#implementation ViewNumberOne
- (void)loadView
{
[super loadView];
button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(110, 190, 100, 20);
[button setTitle:#"Push Me!" forState:UIControlStateNormal];
[button addTarget:self action:#selector(pushAnotherView) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
- (void)pushAnotherView;
{
ViewNumberTwo *view2 = [[ViewNumberTwo alloc] init];
[self.navigationController pushViewController:view2 animated:YES];
[view2 release];
}
ViewNumberTwo.h
#import <UIKit/UIKit.h>
#interface ViewNumberTwo : UIViewController
{
UILabel *label;
}
#end
ViewNumberTwo.m
#import "ViewNumberTwo.h"
#implementation ViewNumberTwo
- (void)loadView
{
[super loadView];
label = [[UILabel alloc] init];
label.text = #"I am a label! This is view #2";
label.numberOfLines = 2;
label.textAlignment = UITextAlignmentCenter;
label.frame = CGRectMake(50, 50, 200, 200); //whatever
[self.view addSubview:label];
}

Can you skin a UIButton application wide in an iPhone app

Anywhere there is a UIButton in my app i would like it to have a specific background image. This background image will always be the same.
What i dont want to have to do is call a method on every button that i put into my UI.
Can i do this via a category or something similar?
You can't change global appearance of your button via simple code (in current SDK).
BUT, You can subclass your UIButton. For example:
.h
#interface MyButton : UIButton
#end
---
.m
#implementation MyButton
// your customization code
#end
And if you want to insert an UIButton instance like:
UIButton *button = // init your button
// customize your button
[self.view addSubview:button];
you have to change UIButton to MyButton
Mybutton *button= // init your button
[self.view addSubview:button];
Don't forget about #import "MyButton.h" in your .m / .h file.
EDIT: Where should you make customizations:
#implementation UIButton (MyCategory)
+ (id)buttonWithFrame:(CGRect)frame {
return [[[self alloc] initWithFrame:frame] autorelease];
}
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// HERE YOU CAN DO SOME CUSTOMIZATION
}
return self;
}
Then, somewhere in your viewController:
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(x, y, width, height)];
or:
UIButton *btn = [UIButton buttonWithFrame:CGRectMake(x, y, width, height)];

create uibutton subclass

I tried to subclass UIButton to include an activity indicator, but when i use initWithFrame:(since i'm subclassing uibutton i'm not using buttonWithType:) the button doesn't display. Also how would i set the button type in this case?:
my view controller:
ActivityIndicatorButton *button = [[ActivityIndicatorButton alloc] initWithFrame:CGRectMake(10, 10, 300, 44)];
[button addTarget:self action:#selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Older Posts..." forState: UIControlStateNormal];
[cell addSubview:button];
[button release];
my activityindicatorbutton class:
#import <Foundation/Foundation.h>
#interface ActivityIndicatorButton : UIButton {
UIActivityIndicatorView *_activityView;
}
-(void)startAnimating;
-(void)stopAnimating;
#end
#implementation ActivityIndicatorButton
- (id)initWithFrame:(CGRect)frame {
if (self=[super initWithFrame:frame]) {
_activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
_activityView.frame = CGRectOffset(_activityView.frame, 60.0f, 10.0f);
[self addSubview: _activityView];
}
return self;
}
-(void) dealloc{
[super dealloc];
[_activityView release];
_activityView = nil;
}
-(void)startAnimating {
[_activityView startAnimating];
}
-(void)stopAnimating {
[_activityView stopAnimating];
}
#end
Favour composition over inheritance.
Create a UIView which contains the components you need and add them to your view.
I ran into a similar situation, and agree with Jeff that you don't really need to subclass UIButton. I solved this by subclassing UIControl, and then overriding layoutSubviews to do all of the configuration of the views I wanted on my "button". It's a much more simple implementation that subclassing UIButton since there does seem to be some hidden mojo going on under the hood. My implementation looked like this:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.opaque = YES;
self.imageView = [[UIImageView alloc] initWithFrame:CGRectZero];
[self addSubview:self.imageView];
self.textLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self addSubview:self.textLabel];
}
return self;
}
And layoutSubviews looked like this:
- (void)layoutSubviews {
[super layoutSubviews];
// Get the size of the button
CGRect bounds = self.bounds;
// Configure the subviews of the "button"
...
}
I have created a custom class, preferring composition over inheritance and it works perfect. My custom class has a button and it knows it's MCContact object. Also it draws a proper button and calculates frames automatically using MCContact object, that is passed.
Header file sample:
#import <UIKit/UIKit.h>
#protocol MCContactViewDelegate;
#interface MCContactView : UIView
{
}
#property (nonatomic, strong) MCContact *mcContact;
#property (nonatomic, weak) id <MCContactViewDelegate> delegate;
- (id)initWithContact:(MCContact*)mcContact delegate:(id <MCContactViewDelegate>)delegate;
#end
#protocol MCContactViewDelegate <NSObject>
- (void)contactViewButtonClicked:(MCContactView*)contactView;
#end
Implementation file:
#import "MCContactView.h"
#interface MCContactView()
{
UIButton *_button;
}
#end
#implementation MCContactView
- (id)initWithContact:(MCContact*)mcContact delegate:(id <MCContactViewDelegate>)delegate
{
self = [super initWithFrame:CGRectZero];
if (self) {
GetTheme();
_mcContact = mcContact;
_delegate = delegate;
_button = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *normalBackgroundImage = [[UIImage imageNamed:#"tokenNormal.png"] stretchableImageWithLeftCapWidth:12.5 topCapHeight:12.5];
[_button setBackgroundImage:normalBackgroundImage forState:UIControlStateNormal];
UIImage *highlightedBackgroundImage = [[UIImage imageNamed:#"tokenHighlighted.png"] stretchableImageWithLeftCapWidth:12.5 topCapHeight:12.5];
[_button setBackgroundImage:highlightedBackgroundImage forState:UIControlStateHighlighted];
_button.titleLabel.font = [theme contactButtonFont];
[_button setTitleColor:[theme contactButtonTextColor] forState:UIControlStateNormal];
[_button setTitleEdgeInsets:UIEdgeInsetsMake(4, 6, 4, 6)];
NSString *tokenString = ([allTrim(mcContact.name) length]>0) ? mcContact.name : mcContact.eMail;
[_button setTitle:tokenString forState:UIControlStateNormal];
[_button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
CGSize size = [tokenString sizeWithFont:[theme contactButtonFont]];
size.width += 20;
if (size.width > 200) {
size.width = 200;
}
size.height = normalBackgroundImage.size.height;
[_button setFrame:CGRectMake(0, 0, size.width, size.height)];
self.frame = _button.frame;
[self addSubview:_button];
}
return self;
}
- (void)buttonClicked:(id)sender
{
[self.delegate contactViewButtonClicked:self];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
You have a pretty obvious problem that concerns your dealloc method: [super dealloc]; must be called AT THE END of your implementation, or else the line after that will try to access a memory space (the ivar space) that has been already deallocated, so it's going to crash.
For the other problem, I'm not sure it's a good idea to put an activity monitor as the subview of a button in general...
You don’t really want to subclass UIButton. It’s a class cluster, so individual instances will be something like UIRoundRectButton or some other private Apple class. What are you trying to do that requires a subclass?