I am trying to create a UIButton in code, and this code is in some methods which will get called from some class.
Here is the method that creates the button
-(void)createButton
{
NSLog(#"createButton");
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"Get Friends" forState:UIControlStateNormal];
[button setFrame:CGRectMake(100, 100, 100, 50)];
[button addTarget:self action:#selector(loadTableView) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
but it never appears in the view, what's wrong?
Edit: if I call this method from viewDidLoad then it works!
Edit 2: the method is in the ViewController class and I call it from MyFacebooDelegate class
here is the call code from MyFacebooDelegate class:
ViewController *m2 = [[ViewController alloc] init];
[m2 createButton];
When you create a new ViewController using ViewController *m2 = [[ViewController alloc] init]; it is not the same ViewController that is handling the screen.
Instead of allocating a ViewController, you should be using the one that's created when the application starts.
May be your view is not loaded from Nib yet at the moment. If you created view by instantiating
[[UIViewController alloc] initWithNibName:#"someNibName" bundle:nil];
than view controller will be created and start to load view from Nib asynchronously. So, if UIViewController is instantiated, that does not mean UIView is. So, that's why your button work when created from -viewDidLoad: callback.
Related
Here is my problem (See illustration bellow):
I have a main screen (MainViewController) from which i present a form modal (ModalController) embedded in a Navigation controller.
After completing the form I want to present the result to the user and dismiss the modal.
The result is shown with a ItemViewController and it should be pushed on the main stack, i.e. in a navigation controller and if the user presses back, he returns to the main screen.
My problem is how to dismiss the modal and push the new view controller at the same time?
What I tried:
dismiss the modal and push the new view controller in the completion block using
self.parentViewController.navigationController pushViewController:itemViewController but only the modal is dismissed.
push the view controller the same way then dismiss, also without effect.
unwind the modal to the main screen and from the unwindSegue method, instantiate and push the new view controller. Unfortunately, the code below has the same effect..
- (IBAction)unwindSegue:(UIStoryboardSegue *)segue {
ItemViewController *viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ItemViewController"];
[self.navigationController pushViewController:viewController animated:YES];
}
Might be important
In the storyboard, ItemViewController is embedded in a NavigationController since it is defined as on the picture below:
Maybe this can help:
in viewDidLoad method of ItemViewController:
UIImage *backButtonImage = [UIImage imageNamed:#"back.png"];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton setImage:backButtonImage
forState:UIControlStateNormal];
backButton.frame = CGRectMake(0, 0, 55, 45);
[backButton addTarget:self
action:#selector(goHome)
forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
self.navigationItem.leftBarButtonItem = backBarButtonItem;
- (void)goHome{
NSArray *array = [self.navigationController viewControllers];
[self.navigationController popToViewController:[array objectAtIndex:0] animated:YES];
}
I have created several ViewControllers in a storyboard that each have their own class files. In AppDelegate I have programatically generated a UINavigationController that exists at the top of the app for every page. This will have two buttons that will be the same for every ViewController, one will load a ViewController called 'settings' and one will fire a method that reveals a side menu.
Screen shots to illustrate:
Currently, each ViewController has a button in the top left, that when pressed moves the current ViewController across revealing the menu below.
This works fine but what I want is for this button to be removed and replaced with the button that is on the NavigationController (currently place holder menu button seen in the purple NavigationController).
How do I implement the code that moves the ViewController in the AppDelegate, what the UINavigationController is generated?
AppDelegate.m
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
MainViewController* mainVC = [mainStoryboard instantiateInitialViewController];
UINavigationController *navVC = [[UINavigationController alloc] initWithRootViewController:mainVC];
[mainVC setTitle:#"Congress app"];
UIBarButtonItem *showSettingsButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:#selector(showSettings:)];
UIBarButtonItem *showMenuButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"menuButton.png"] style:UIBarButtonItemStylePlain target:self action:#selector(revealMenu:)];
mainVC.navigationItem.leftBarButtonItem = showMenuButton;
mainVC.navigationItem.rightBarButtonItem = showSettingsButton;
[self.window setRootViewController:navVC];
[_window makeKeyAndVisible];
return YES;
}
- (IBAction)revealMenu:(id)sender
{
// This obviously won't work but what should go here instead?
// Something like get instance of MainViewController and fire it's reveal menu
// method but passing the current ViewController Id and running slidingViewController anchorTopViewTo:ECRight on that?
[self.slidingViewController anchorTopViewTo:ECRight];
}
MainViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.layer.shadowOpacity = 0.75f;
self.view.layer.shadowRadius = 10.0f;
self.view.layer.shadowColor = [UIColor blackColor].CGColor;
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"MenuVC"];
}
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
self.menuBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_menuBtn.frame = CGRectMake(8, 80, 34, 24);
[_menuBtn setBackgroundImage:[UIImage imageNamed:#"menuButton.png"] forState:UIControlStateNormal];
[_menuBtn addTarget:self action:#selector(revealMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.menuBtn];
NSLog(#"MainVC loaded");
}
- (IBAction)revealMenu:(id)sender
{
[self.slidingViewController anchorTopViewTo:ECRight];
}
You're better off not doing that...
This isn't app delegate responsibility
There are 3rd party implementations on github / CocoaControls which offer this and manage the navigation bar
It is much better to rework your current view hierarchy than to force a connection from the app delegate.
The responsibility of the app delegate is to respond to app level events (like foreground / background notifications). It might be involved in setting up the initial UI but other than that is should do basically nothing.
I need to have a UIButton (with a class of RtnBtn) which basically replicates the back button action used in the navigation bar action at the end of a process - I'm fairly new to IOS dev and I'm not sure how to approach this - should it be done via a push or is there a better option to apply coded action directly to the button?
Can you post some code here, what you have done?, you can add custom back button by below code,
UIButton *buttonBack = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonBack setBackgroundImage:YOURImage forState:UIControlStateNormal];
[buttonBack addTarget:self action:#selector(backPressed) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *backButton = [[[UIBarButtonItem alloc] initWithCustomView:buttonBack] autorelease];
self.navigationItem.leftBarButtonItem = backButton;
Method to handle event,
-(void)backPressed
{
[self.navigationController popViewControllerAnimated:YES];
}
You need to create the button, specify a selector as it's action, and in that method call popViewController:animated: on your navigation controller.
If I did not understand wrong, you need this;
[self.navigationController popViewControllerAnimated:YES];
I am trying to add a custom UIBarButtonItem to my navigationItem. This button will be available in all my view controllers. so instead of adding it to each viewDidLoad method in each viewDidLoad I am trying to add it in my application Delegate class in a seperate method that i will call in the viewDidLoad method.
Here is my Code:
UIImage* image = [UIImage imageNamed:#"some-header-icon.png"];
CGRect frame = CGRectMake(0,0,image.size.width,image.size.height);
UIButton* hellBtn = [[UIButton alloc] initWithFrame:frame];
[hellBtn setBackgroundImage:image forState:UIControlStateNormal];
[hellBtn setShowsTouchWhenHighlighted:NO];
[hellBtn addTarget:self action:#selector(goToHell) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem* rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:hellBtn];
[self.nav.navigationController.navigationItem setRightBarButtonItem:rightBarButtonItem];
[hellBtn release];
[rightBarButtonItem release];
if I replace the same code blog in any viewDidLoad of any viewController and change
[self.nav.navigationController.navigationItem setRightBarButtonItem:rightBarButtonItem];
By:
[self.navigationItem setRightBarButtonItem:rightBarButtonItem];
It works perfectly.
Any Idea Why?
Create a subclass of UIViewController for ex. UIViewControllerBase, override viewDidLoad method and inside it create your rightBarButtonItem and set it. Then make all of your controllers inherit UIViewControllerBase - simple OOP scenario.
You should not use this self.nav.navigationController since nav is a UINavigationController then dont get the .navigationController
Just use [self.navigationItem setRightBarButtonItem:rightBarButtonItem];
I'm new to iOS development. To keep my iOS app nicely compartmentalised I'd like to create both the UIView and the UIViewController programatically, and tie them together once created.
So, I do the following: in my view controller I have this:
-(void)loadView {
NSLog(#"HPSMainMenuViewController loadView starting");
HPSMainMenuView* mainmenuView = [[HPSMainMenuView alloc]initWithFrame:CGRectZero];
self.view = mainmenuView;
}
and in my View I have this:
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSLog(#"HPSMainMenuView initWithFrame starting");
[self setup];
}
return self;
}
-(void)setup {
UIButton* btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.tag = E_PROFILE_BUTTON;
[btn setTitle:#"Option1" forState:UIControlStateNormal];
[self.view addSubview:btn ];
btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.tag = E_CONTACTS_BUTTON;
[btn setTitle:#"Option2" forState:UIControlStateNormal];
[self.view addSubview:btn ];
self.title = #"Hello";
}
Is this the right way to do this (given I want full programmatic control). It seems wrong to dynamically build the view within the ViewController hence my approach where I am building the view within an actual UIView class.
Lastly, I'm using loadView; should I be using viewDidLoad? If so, why?
Thanks very much.
What you are doing is correct, and actually good. Many developers keep their view controllers and views heavily tied together but if you want to keep them separate then that's great.
loadView is where you should be creating and initializing everything. viewDidLoad can be called multiple times if the view is unloaded/reloaded due to memory warnings (for example). So viewDidLoad is where you would restore saved state, make your view correctly reflect your model, or any other initialization that you can't do in loadView.