I subclassed UINavigationController and added a UIView to the bottom of its view in viewDidLoad (as a custom UITabBar or UIToolbar).
How do I set the height of the view of every UIViewController that this UINavigationController pushes?
How do I set the height of the view of every UIViewController that
this UINavigationController pushes?
View controllers don't have height -- the views they manage do.
To do what you propose, I suppose you override the accessors for the delegate property so that you could intercept any calls to -navigationController:willShowViewController:animated: and resize the child view controller. That doesn't seem like a very satisfying solution, though.
Do you have so many view controllers that you can't add your tool bar to each one's view hierarchy?
Related
I have a UIViewController's view inside my UIScrollView subclass. The problem is my UIViewController is not getting the willRotate delegate called when I rotate the device. This is probably because UIView does not have a rotation delegate implemented in it. What is the best way to solve this?
Basically the structure is I have a MainViewController in which it has a UIScrollView. Inside this UIScrollView I have a subviews, which is the view of a bunch of UIViewControllers. The issue now is, it's not getting rotation calls when I rotate. One way to deal with this is to delegate from the MainViewController to those respective UIViewController. Is there a better/elegant way to solve this?
I am adding it as a subview from my UIScrollView not my MainViewController and you can't do UIViewControllers containment from a UIView. Correct me if I am wrong
I think you're going against the MVC pattern. You can't have a controller inside a view; instead you should have a controller that mediates the communictaion between the view and the user's input. In your case you could set the scrollview as self.view of the MainViewController, and then add the viewcontrollers views as subviews.
Watch the video that I posted in my comment: https://developer.apple.com/videos/wwdc/2011/?id=102
Here is a short summary of view controller containment, which is the design you are looking for, not combining all your logic into one view controller or using delegation for something that is built into the SDK.
A view controller has a view and provides logic for that view and most likely some of it's subviews.
You might have a complex view hierarchy and complex logic for specific views in that hierarchy that warrant the view to have it's own view controller controlling it and it's subviews.
Say you have a MainViewController and it's view is a UIScrollView (or subclass). Inside that scrollview, you might have an assortment of complex views that warrant their own controller, so you have a class, SubViewController that has the subview of the scrollview as it's view.
SubViewController needs to have rotation and appearance method callbacks working correctly in order to implement your logic for the the subview and handle layout changes.
[mainViewControllerInstance addChildViewController:subViewControllerInstance];
But, wait. The subview is still not in the view hierarchy.
[mainViewControllerInstance.view addSubView:subViewControllerInstance.view];
You have successfully created a valid view controller hierarchy of two view controllers and set up the associated view hierarchy of their views.
You will now have the appropriate callbacks functioning, as MainViewController will forward them to SubViewController.
EDIT:
See the documentation for an over view of view controller containment: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
I'm working on an app that has three table view controllers in a navigation stack. The root view controller and the second VC have toolbars, but I want to add a subview to the second view controller like this. (The color is just there for visualization.)
I want to add the view programmatically, since I haven't been able to do it with IB without major headaches. Right now, I've been able to kind of get what I want by drawing a UIView in the second view controller like this:
- (void)viewDidLoad {
[super viewDidLoad]
UIView *detailView = [[UIView alloc] initWithFrame:CGRectMake(0, 392, 320, 44)];
detailView = [UIColor redColor];
[self.navigationController.view addSubview:detailView];
[detailView release];
}
The problem with this approach is that once the UIView is loaded in the second view controller, it stays loaded and is drawn in the third and root view controllers. I've tried a variety of methods of removing the UIView, including setting the detailView to nil in viewDidUnload, calling removeFromSuperview in didSelectRowAtIndexPath (which removed the view from the whole stack).
I've also tried adding the subview to self.view, but that pushes it below the visible area of the table view, so I have to scroll up to see it, and it snaps back down when I let go.
Clearly, adding this subview to the navigation controller is not the best way to do what I want, but I'm at a loss as to where to go from here.
As you've already discovered, you definitely should not be reaching up into the navigation controller's view.
You want your SecondViewController to be an UIViewController that implements the UITableViewDelegate and UITableViewDataSource and whose view lays out the UITableView and the UIView you wish to use for your stationary 'footer' in it's own main UIView.
It helps to keep in mind that UITableViewController is ultimately is just a convenience for creating a view controller whose view consists entirely of a UITableView.
Anyway, rather than attempt to put a pile of that code inline in this answer, you can browse it (or svn co) from this read-only svn repo.
EDITED (now that it's not midnight, putting some code/explanation directly in answer):
For the controller to be pushed onto the nav stack that needs the footer create a new UIViewController-based class (do NOT check the 'UITableViewController subclass' box in the template selection dialog).
Add instance variables for the UITableView and the UIView that is to be the extra bottom view.
#interface SecondViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
UITableView* tableView;
UIView* customFooterView;
}
#property (nonatomic,retain) IBOutlet UITableView* tableView;
#property (nonatomic,retain) IBOutlet UIView* customFooterView;
#end
In IB add a UITableView and UIView to the existing root view for the controller and lay them out as desired (probably worth altering the auto-resize parameters too if your app can be used in both landscape and portrait). Hook up the two views to the outlets defined for them in the "File's Owner" and also ensure you hook up the UITableView's delegate and dataSource properties to point at the "File's Owner."
Then just implement the UITableViewDelegate and UITableViewDataSource protocols as appropriate for your application.
If you want to lay out the entire 'footer' view in IB then go right ahead. Otherwise you can easily add items programmatically in viewDidLoad (and remember to tear it down in viewDidUnload).
I don't like the approach. You should put your table view inside another view, and put your detail view together in that view.
Despite of that, I think you can remove your view in viewWillDisappear method of your view controller. I also notice that you did not keep your detailView as a private variable, which you should do because you need to reference it when removing it later (I still wonder how you have done it.)
Note that viewDidUnload is called in case of view unloading (i.e. releasing from its controller), so it is not related to navigation.
Not sure which behavior you're looking for but try one of these:
Assign the detailView to the tableFooterView property of the tableview on the second VC.
Reduce the height of the table view and add the detailView to self.view.
I have a NIB with a UIView that contains some UILabels, UIButtons etc. and a UIViewController that is loading a UITableView from a detached NIB.
I want the UITableView in the UIViewController to be positioned below my UIView, but whenever I add it in Interface Builder it takes up the whole screen, and my UIView becomes part of the UIViewController.
How can I make sure the UITableView in my UIViewController appears below the UIView?
I want the UIViewController to be
positioned below my UIView
What you mean is you want the UIViewController's view positioned below your existing UIView. View controllers do not show up on screen themselves.
Create a new UIView instance in your nib, position it where you want, and assign it to be the view for the view controller.
I have a UINavigationController with a UIViewController (vc1) as the "root view controller". There are 3 views in the UIViewController:
HeaderView(UIViewSubclass)
UITableView (custom frame)
FooterView(UIViewSubclass)
The reason that the header/footer view are separate from the uitableview is because they need to be stationary and only allow the uitableview to scroll. When the vc1 is loaded everything is PERFECTLY in place and behaves as expected. However, when click on of the cell rows, navigate to vc2 and then navigate back to the vc1 my tableview is now "under" the uinavigationbar.
Note:
The root view controller (vc1) is a subclass of uiviewcontroller so that I could change the frame size for the tableview. The frame for the tableview is set in IB as (0,0, 320,300). As I stated before when the vc1 is originally loaded the tableview is aligned perfectly under the headerview, it is just when I navigate back to vc1 from vc2.
I have tried setting autoresizingMask to UIViewAutoresizingFlexibleTopMargin in viewDidLoad, but to noavail. All suggestions are greatly appreciated
I fixed my problem. The problem was related to an issue with Three20 ThumbnailViewController
I'm having a problem getting my view to be sized properly when created via -loadView. It seems that my view frame is always (0, 0, 320, 460), even when the view/controller is nested inside a UINavigationController and/or UITabBarController. Is there a way to detect programmatically when my view controller is nested within these items, so that I can set the proper frame? My loadView is just setting up a nested UIScrollView that should match exactly the visible size on the screen (460px is too tall when there is a tab bar and nav bar visible).
The reason I'm not hardcoding these values is that I would like this view controller to be reusable and work in all scenarios.
There are a few properties of in UIViewController that might be of interest here:
navigationController
tabBarController
If these are not nil you should be able to tell if you need to resize your view or not.
Do not layout your views in loadView: or viewDidload: without a nib. Do it in viewWillAppear:, the main view's frame is properly at that time.