UINavigationController addSubview - ios

I have a UINavigationController class, I want to add on a button with the method addSubview but its not working
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
UIButton *testbtn = [[UIButton alloc] initWithFrame:CGRectMake(20, 90,28,20)];
[self.view addSubview:testbtn];
}
return self;
}

I assume because you're trying to do this on a navigation controller, you want a bar button item on the toolbar. You need to do this in the UIViewController, not the UINavigationController:
UIBarButtonItem * doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonSystemItemDone
target:self
action:#selector(buttonPressed:)];
[self.navigationItem setRightBarButtonItem:doneButton];
Also, you should grab a cup of coffee and read through the "overview" section of the UINavigationController class reference. It'll take about 10 minutes and you'll be happy you did.
If I'm wrong, and you do want a UIButton (not a UIBarButtonItem), you also need to do that in a UIViewController subclass. Also, you should use its factory method, not a typical alloc/init:
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame = CGRectMake(20, 90,28,20)

I don't believe you can add a button to a UINavigationController - it doesn't actually have a view of its own. The UINavigationController is more of a behind-the-scenes organizer for holding and displaying other UIViewControllers.
You'll need to take your [self.view addSubview:testbtn] and put that in the code of a UIViewController, instead of in the code for the UINavigationViewController. And as David Doyle pointed out in his answer, it's considered better practice to put something like that in viewDidLoad rather than in initWithNibName.

If you want to modify a View Controller's view, its not a good idea to do so in the init method. The nib file that extracts the resources that create the View Controller's view takes a small amount of time to complete.
You're better off modifying the View Controller's view by overriding the method -[UIViewController viewDidLoad] like so:
- (void)viewDidLoad
{
UIButton *testbtn = [[UIButton alloc] initWithFrame:CGRectMake(20, 90,28,20)];
[self.view addSubview:testbtn];
}

Related

ViewController occasionally miss in responder chain?

i meet a very strange thing today: that my custom ViewController occasionally miss in responder chain
first i have a custom UIView, with a UIButton as its subview, then i set the target-action as usual:
[closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
of course, i implement the closeButtonPressed method in my custom UIViewController
in most time, it just worked fine. but occasionally, my ViewController miss the tap event, and finally i found that , the tap event pass to the AppDelegate, and the closeButtonPressed method in AppDelegate is invoked!
i spent a whole day in this problem, and still don't know why. can you give me a clue? thanks a lot. following is the code, hope it can help:
the code to init and present my ViewController and View:
YLSRegisterStepOneViewController *step1Controller = [[YLSRegisterStepOneViewController alloc] initWithNibName:nil bundle:nil];
step1Controller.view = [[YLSRegisterStepOneView alloc] initWithFrame:CGRectMake(0, 0, 540, 720) OperType:operType];
step1Controller.modalPresentationStyle = UIModalPresentationFormSheet;
step1Controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:step1Controller animated:YES completion:nil];
the code of the UIView:
UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
closeButton.frame = CGRectMake(10, 10, 50, 50);
[closeButton setTitle:NSLocalizedString(#"button_close", #"") forState:UIControlStateNormal];
[closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:closeButton];
the code of the UIViewController:
-(void) closeButtonPressed
{
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];// to dismiss self
}
additional: aside the UIButton, there is a UITextField. when this problem happens, if i click the UITextField, then click the UIButton, UIViewController works fine
You set controller property of YLSRegisterStepOneView like this:
YLSRegisterStepOneViewController *step1Controller = [[YLSRegisterStepOneViewController alloc] initWithNibName:nil bundle:nil];
YLSRegisterStepOneView *step1View = [[YLSRegisterStepOneView alloc] initWithFrame:CGRectMake(0, 0, 540, 720) OperType:operType];
step1Controller.view = step1View;
step1View.controller = step1Controller;
You add the button in YLSRegisterStepOneView's initWithFrame: method, don't you?
So [closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside]; self.controller here is still nil.
step1View.controller = step1Controller; is called after [closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
updated:
You say the responder chain confuses you, I think the problem is that you assign view controller's view property like this step1Controller.view = step1View; which is not recommended. If you want to use your custom view as viewcontroller's view, do this:
Override loadView method in viewcontroller.
You can override this method in order to create your views manually. If you choose to do so, assign the root view of your view hierarchy to the view property. The views you create should be unique instances and should not be shared with any other view controller object. Your custom implementation of this method should not call super.
- (void)loadView
{
YLSRegisterStepOneView *step1View = [[YLSRegisterStepOneView alloc] initWithFrame:CGRectMake(0, 0, 540, 720) OperType:operType];
self.view = step1View ;
}
I don't see where you are setting the controller property of the custom view which you are passing here:
[closeButton addTarget:*self.controller* action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
I think if you create/set the controller property in your view it would solve the problem (unless you are already doing it but code is not here).

UITableView inside popover will not scroll

I am trying to fix someone's code and am running into a problem. Here is the situation:
I have a full screen UIViewController that has a bottom bar button. When I press that button, it shows a popup view controller in the bottom left of the screen. That view controller inside the popup also has a button, and when I press THAT button it pushes a new view controller into my popup window. That new view controller is a UITableView that can have some large number of elements. The problem is that when I try to scroll down to see some offscreen elements, the scroll bounces back to the first position in the table, i.e. it does not really scroll.
More specifically here is some code:
In FullScreenVC.h:
#property (nonatomic, retain) NSMutableArray* stuffInList;
#property (nonatomic, retain) UIPopoverController *namePopover;
#property (nonatomic, retain) UINavigationController *nameNav;
#property (nonatomic, retain) UIBarButtonItem* addButton;
Inside FullScreenVC buttonPressed (called when addButton is pressed):
FirstPopupVC *vc=[FirstPopupVC alloc] initWithNibName#"FirstPopupVC" bundle:nil];
vc.delegate=self;
vc.stuffInList=self.stuffInList; // This is just the NSArray of list items
self.nameNav = [[[UINavigationController alloc] initWithRootViewController:vc] autorelease];
self.namePopover = [[[UIPopoverController alloc]
initWithContentViewController:self.nameNav] autorelease];
[vc release];
[self.namePopover presentPopoverFromBarButtonItem:self.addButton
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
In other words, the FirstPopupVC object vc is the root view controller of a UINavigationViewController nameNav, and nameNav is the navigationcontroller that is the content inside the namePopover UIPopoverController. I think the last line launches FirstPopupVC as a popup from the addButton. Note also that the XIB file FirstPopupVC.xib is a simple NIB file that has a few simple views (label etc) and a little button that a user can press to get the second popup, as we'll see.
Inside FirstPopupVC we have:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// some other irrelevant initialization stuff here ...
self.contentSizeForViewInPopover = CGSizeMake(320, 340);
}
return self;
}
-(void)littleButtonClicked:(id)sender {
SecondPopupVC * secondVC=[[SecondPopupVC alloc]
initWithNibName:"#SimpleTableView" bundle"nil];
secondVC.delegate=self;
secondVC.stuffInList=self.stuffInList;
[self.navigationController pushViewController:secondVC animated:YES];
[secondVC release];
}
This of course presents the second view controller inside the popop.
Inside SecondPopupVC we have:
- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.contentSizeForViewInPopover = CGSizeMake(320, 340);
}
return self;
}
Apparently the contentSizeForViewInPopover call here will set the size of the popover view with the table view. It looks like this is called inside initWithNibName in both the first and second view controllers.
So again, the problem is that if my listOfStuff is large, ie if the set of items in the table is large, then the table will not stay scrolled beyond the first visible set of rows. I can scroll down to see these items but as soon as I release the mouse pointer (on the emulator) or my finger (on the device), it bounces back to the top of the list.
I tried to add autoresizingmak code as discussed in table view in popover is not scrolling but that didn't work for me.
So how can I fix the above code so that my table stays scrolled when I try to scroll it?
Well, it appears that the problem has something to do with the fact that secondVC is created from a NIB file rather than programmatically. I tried doing this instead:
-(void)littleButtonClicked:(id)sender {
SecondPopupVC * secondVC=[[SecondPopupVC alloc] init];
CGSize contentSize = CGSizeMake(320, 320);
UIView* popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,
contentSize.width, contentSize.height)];
popoverView.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight);
UITableView *tblView = [[UITableView alloc]initWithFrame:popoverView.bounds];
tblView.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight);
tblView.delegate = secondVC;
tblView.dataSource = secondVC;
tblView.rowHeight = 44;
[popoverView addSubview:tblView];
secondVC.view = popoverView;
secondVC.contentSizeForViewInPopover = contentSize;
secondVC.stuffInList=self.stuffInList;
[self.navigationController pushViewController:secondVC animated:YES];
[secondVC release];
}
and guess what? It works fine. So why would there be such a problem when SecondPopupVC is initialized from a NIB file rather than using code?

Gap when changed of viewcontroller

I'm implementing an application, in which i use several view controllers. But i've found a strange behaviour of my app' when it changes of viewcontroller. Let me explain :
We are in a first viewcontroller, his init method is :
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
Menu = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
self.view.backgroundColor = [UIColor greenColor];
[self.view addSubview:Menu];
[Menu release];
}
return self;
}
After that, to change of viewcontroller and pass from the first to another, i call this method :
-(void)GoPlay
{
if (!parametresviewcontroller)
{
parametresviewcontroller = [[ParametresViewController alloc]init];
}
UIView *menuView = menuviewcontroller.view;
UIView *paramView = parametresviewcontroller.view;
[menuviewcontroller viewWillAppear:NO];
[parametresviewcontroller viewWillDisappear:NO];
[menuView removeFromSuperview];
[self.view addSubview:paramView];
[menuviewcontroller viewDidAppear:NO];
[parametresviewcontroller viewDidDisappear:NO];
}
So the init method of the second viewcontroller is called, i put it next :
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
Parametres = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
Parametres.backgroundColor = [UIColor redColor];
[self.view addSubview:Parametres];
[Parametres release];
}
return self;
}
And the result is :
Why this strange behavior occured ? I really don't understand why the is a gap between the first and the second one...
Thank you ! =)
Ok, The problem is, both the class Is a UIViewController and you have set statusbar for both ViewController's View in XIB file. When you set StatusBar Than the view frame changes its y to 20 pixel below means you have set it to 0 but originally it is 20.
So when you add subView second ViewController's view on the first ViewController's View before doing this set:
secondViewController.view.frame = firstViewController.view.bounds;
. This will solve your problem.
First of all, DO NOT CALL viewWillAppear, viewWillDisappear, viewDidAppear and viewDidDisappear by yourself, this methods are called by the OS in some specific points of a UIViewController life-cycle.
Second, initWithNibName is not the proper method for adding subviews to the controller's view, for that you should use viewWillAppear, viewDidAppear or viewDidLoad.
Third, what you are doing is not changing of view controllers is simply adding a view controller's view to another view controller view, for changing UIViewController you should use addChildViewController: and removeFromParentViewController methods or use UINavigationController
I've found a solution : iPhone hiding StatusBar shifts view down by 20 pix
Use
[self setWantsFullScreenLayout:YES];
in the init method in my case.
Thank you all !

UINavigationController as child of UINavigationController

I don't know if the title explains the question itself but here it is ...
I have a UINavigationController which is the parentViewController of a UINavigationController. The thing is the childViewController behaves strange, when I add it as a child it first has the gap for the statusBar (it doesn't occupy the entire screen) and if I "solve" that "bug" by hiding and showing the navigationBar, the gap goes away but now the child doesn't respect the frame I set manually.
Then I tried to continue and when I presented a modal on the child and dismiss it, the entire child goes away ...
What would be wrong there? The parent-child relationship with both containers or what?
Thanks in advice
EDIT: Here's an example project showing the strange behavior
http://www.mediafire.com/?8saa68daqfkf335
EDIT 2: I found a solution actually and I didn't find it really clear on Apple Docs, it says the childViewControllers take its frame from the parentViewController they belong to, but it doesn't say that if the parentViewController "reappears" (like a push on it) the childViewControllers get resized again by the parentViewController frame ... Hope this helps anyone
I believe it would be better to present the second navigation view controller as a modal view controller.
For example, replace your current presentController selector with something like:
- (void)presentController:(id)sender {
ChildViewController1 *cvc = [[ChildViewController1 alloc] initWithNibName:#"ChildViewController1" bundle:nil];
nc3 = [[UINavigationController alloc] initWithRootViewController:cvc];
nc3.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:nc3 animated:YES completion:nil];
UIBarButtonItem *i = [[UIBarButtonItem alloc] initWithTitle:#"X" style:UIBarButtonItemStyleBordered target:self action:#selector(close)];
cvc.navigationItem.leftBarButtonItem = i;
}
Then, your close selector could become:
- (void)close {
[nc3 dismissViewControllerAnimated:YES completion:nil];
}
(though I'd recommend moving the creation of the button and handling the close actually in ChildViewController1.m).
Of course, this would take all the creation of the navigation controller off ViewController.m's viewDidLoad selector:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor blueColor];
UIButton *b = [UIButton buttonWithType:UIButtonTypeRoundedRect];
b.frame = CGRectMake(0, 100, 100, 40);
[b setTitle:#"present" forState:UIControlStateNormal];
[b addTarget:self action:#selector(presentController:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:b];
}
Hope it works!

How to switch views from barbuttonitem?

I have an overlay in which I've created a toolbar containing a done button.
The name of the selector for done button is doneButtonPressed.
Now when I click done button, how do I get a new nib view? Let's us assume I created a nib named TestViewController.
-(void)doneButtonPressed {
//What goes here?
}
If you want to instantiate a UIViewController from a nib you can use the following line of code:
UIViewController *viewControllerName = [[UIViewController alloc] initWithNibName:(NSString *) bundle:(NSBundle *)];
Then you can present the view modally with:
[self presentModalViewController:(UIViewController *) animated:(BOOL)];
Now if you are using a storyboard, then you could just instantiate a view controller from a storyboard object.
Not sure if this is what you are looking for, but you could turn your view into a "container view". To do that you will need to create subviews and then just switch them out. I did this when I wanted a menu to control a different view.
[self.view insertSubview:(view you want to insert) atIndex:0];
Then when you want to switch it out:
[[[self.view subviews] objectAtIndex:0] removeFromSuperview];
[self.view insertSubview:(view you want to replace with) atIndex:0];
EDITED
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(doneButtonPressed:)];
- (void)doneButtonPressed {
SkipQViewController *skipQ = [[SkipQViewController alloc] initWithNibName:#"Name" bundle:bundleName];
[self presentModalViewController:skipQ animated:YES];
}
If that does not work try using: SkipQViewController *skipQ = [[SkipQViewController alloc] init]; to instantiate your view controller.
-EDIT-
Instantiate the view controller as such: SkipQViewController *skipQ = (SkipQViewController *)[[UIViewController alloc] initWithNibName:#"sqvc" bundle:nil];

Resources