I have what is a seemingly simple problem but I cannot find a solution! I have a subclass of UIViewController that is my root view controller, and ten different other UIViewcontrollers that I want to load in as child view controllers when called (one at a time, not all ten on screen at once.)
The root controller has a few buttons whose actions call the respective code to bring up a child view controller. The root view controller is loaded first by the nib and I want to instantiate it with page01ViewController as the first child. But whenever I call the following code, the child view controller is overlayed on top of my rootViewController, hiding all of the control buttons in my root controller!
// RDJrootPageViewController.m
#import "RDJrootPageViewController.h"
#import "RDJhomeScreenViewController.h"
#import "RDJpage01ViewController.h"
#import "RDJpage02ViewController.h"
#import "RDJpage03ViewController.h"
#import "RDJpage04ViewController.h"
#import "RDJpage05ViewController.h"
#import "RDJpage06ViewController.h"
#import "RDJpage07ViewController.h"
#import "RDJpage08ViewController.h"
#import "RDJpage09ViewController.h"
#import "RDJpage10ViewController.h"
#interface RDJrootPageViewController ()
#property (retain, nonatomic) RDJhomeScreenViewController *homeScreenViewController;
#property (retain, nonatomic) RDJpage01ViewController *page01ViewController;
#property (retain, nonatomic) RDJpage02ViewController *page02ViewController;
#property (retain, nonatomic) RDJpage03ViewController *page03ViewController;
#property (retain, nonatomic) RDJpage04ViewController *page04ViewController;
#property (retain, nonatomic) RDJpage05ViewController *page05ViewController;
#property (retain, nonatomic) RDJpage06ViewController *page06ViewController;
#property (retain, nonatomic) RDJpage07ViewController *page07ViewController;
#property (retain, nonatomic) RDJpage08ViewController *page08ViewController;
#property (retain, nonatomic) RDJpage09ViewController *page09ViewController;
#property (retain, nonatomic) RDJpage10ViewController *page10ViewController;
#end
#implementation RDJrootPageViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
currentPage = 1;
self.page01ViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"page01"];
[_page01ViewController.view setFrame:CGRectMake(0, 0, 1024, 768)];
[self addChildViewController:_page01ViewController];
[self.view addSubview:_page01ViewController.view];
[_page01ViewController didMoveToParentViewController:self];
[self.view setUserInteractionEnabled:YES];
}
My problem is similar to the one asked here, but no solution was ever identified:
Return from Child View Controller to Container
Every tutorial I find has the same setup: make your new VC, add it as a childView to self, then add that as a subview to your root view, but it dosen't work.
Anyone know the right way to do this?
You may want to user insertSubview:atIndex:. Using an index of 0 will add the view under all the other views. Alternatively you could have a container view for the views of the page view controllers. This container view needs to be added at index 0 in the view of RDJrootPageViewController. The page view controllers views could be added to the afore mentioned container view.
Hope this helps.
Related
I'm running into a minor complication using IBInspectable properties and not sure if it might have something to do with my xibs and xib usage. I'm trying to reuse a custom control between multiple view controllers. The control is a custom tab manager:
The IBInspectable Attributes are configured in this xib as: First, Second, Third.
Here is the corresponding code for the header file.
IB_DESIGNABLE
#interface TabContainerView : NSView
#property (nonatomic, strong) IBOutlet NSView *view;
#property (weak) IBOutlet TabContentView *contentView;
#property (weak) IBOutlet TabView *firstTab;
#property (weak) IBOutlet TabView *secondTab;
#property (weak) IBOutlet TabView *thirdTab;
#property (nonatomic, strong) IBInspectable NSString *tabOneText;
#property (nonatomic, strong) IBInspectable NSString *tabTwoText;
#property (nonatomic, strong) IBInspectable NSString *tabThreeText;
#end
#import "TabContainerView.h"
#interface TabContainerView ()
#property (nonatomic, strong) NSMutableArray *tabsArray;
#property (nonatomic, assign) NSInteger selectedTabIndex;
#property (weak) IBOutlet NSTextField *tabOneTextField;
#property (weak) IBOutlet NSTextField *tabTwoTextField;
#property (weak) IBOutlet NSTextField *tabThreeTextField;
#end
#implementation TabContainerView
#pragma mark Init
- (id)initWithFrame:(NSRect)frameRect {
NSString* nibName = NSStringFromClass([self class]);
self = [super initWithFrame:frameRect];
if (self) {
if ([[NSBundle mainBundle] loadNibNamed:nibName
owner:self
topLevelObjects:nil]) {
[self configureView];
}
}
return self;
}
#pragma mark Configure View
- (void)configureView{
[self.view setFrame:[self bounds]];
[self addSubview:self.view];
self.tabOneTextField.stringValue = self.tabOneText;
self.tabTwoTextField.stringValue = self.tabTwoText;
self.tabThreeTextField.stringValue = self.tabThreeText;
}
#end
This works fine in the TabContainerView.xib without issue. Now when I attempt to use this control in two different view controllers, I run into problems. Both of my view controllers are also loaded from Xibs.
In view controller 1 I have something like this:
In view controller 1 I've subclassed the custom view to the TabContainerView subclass which works just fine when I run the application. I've also changed the text to be specific for this view controller. List, Map, Filter are the IBInspectable property values for view controller one. In view controller 2 (not shown), I've done the exact same thing, however different IBInspectable property values specific for view controller 2. However, when I run the application the values never update and always stay as First, Second, and Third. I'm not sure if there is something I'm doing that's causing this problem but any help or tips would be appreciated. (IBDesignable seems to give me a lot of warnings where it breaks and not sure if maybe it's just loading the last saved value for the xib.)
Have you imported #import "TabContainerView.h" in controller 2 .h file.
I'm trying to put two NSPopover on two Help Buttons on a .xib file.
To do so, I declared in my .h
#interface ExportPreferences : NSPreferencePane <NSPopoverDelegate>
{
NSWindow *window;
NSPopover *popover;
NSUserDefaults *prefs;
NSMutableArray *myArran;
IBOutlet NSButton *images;
IBOutlet NSPopUpButton *modalities;
IBOutlet NSPathControl *path;
IBOutlet NSPopUpButton *tree;
IBOutlet NSPopUpButton *extension;
}
#property (assign) IBOutlet NSWindow *window;
#property (assign) IBOutlet NSPopover *popover;
#end
And two different methods in my .m :
- (IBAction) showInfoTreePopover {
[[self popover] showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxXEdge];
}
- (IBAction) showInfoTypePopover {
[[self popover] showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxXEdge];
}
Then, in my .xib I declared
A Popover with its Popover View Controller
A Custom View
A Label (on the CV)
And I linked :
The Help Button to its corresponding method (one for the Tree, one for the Type)
The File's Owner to the Popover
The Popover View Controller to the Custom View
Since I do have two NSPopover to implement, I did all of this twice, two Popover, two Popover View Controller, two Custom View, two labels.
When I compile, everything goes right, but when I test it, it appears that only my second Popover shows up on the two buttons. It seems that implementing the second Popover, erased the first one.
how may I patch that ?
Alright, I answered my own question but I think I might give the answer if anyone faces the same problem.
When using two NSPopovers, I had to declare two different Outlets,
NSPopover *treePopover;
NSPopover *typePopover;
Also, two properties
#property (assign) IBOutlet NSPopover *treePopover;
#property (assign) IBOutlet NSPopover *typePopover;
And now, the linking works perfectly.
I have an os x app that uses core data.
I have 3 .xib files in my app, those are:
1. MainMenu.xib
2. MasterTableViewController.xib
3. DetailViewController.xib
When started , app displays a view that has NSTableView with couple of records in it.
I name that view MasterTableViewController
I want when user double click on the row, to hide the "master" view and to display my "detail" view. I named that view DetailViewController.
When double clicked on the row in the NSTableView in the "master" view,nothing happen, "master" view remains visible. What I want is "master" view to dissapear, and "detail" view to appear.
Here is the code that I have right now, and more explanations follows:
AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (nonatomic,strong) NSViewController *mainAppViewController;
#property (weak) IBOutlet NSView *mainAppView;
- (void)changeViewController:(NSInteger)tag;
#property (weak) IBOutlet NSTableView *websitesTableView;
- (void)tableViewDoubleClick:(id)nid;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "MasterTableViewController.h"
#import "DetailViewController.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
- (IBAction)saveAction:(id)sender;
#end
#implementation AppDelegate
NSString *const masterTable = #"MasterTableViewController";
NSString *const detail = #"DetailViewController";
-(void)awakeFromNib {
[_websitesTableView setTarget:self];
[_websitesTableView setDoubleAction:#selector(tableViewDoubleClick:)];
}
- (void)tableViewDoubleClick:(id)nid {
NSInteger rowNumber = [_websitesTableView clickedRow];
NSTableColumn *column = [_websitesTableView tableColumnWithIdentifier:#"websiteUrl"];
NSCell *cell = [column dataCellForRow:rowNumber];
NSInteger tag = 2;
[self changeViewController:tag];
}
- (void)changeViewController:(NSInteger)tag {
[[_mainAppViewController view]removeFromSuperview];
switch (tag) {
case 1:
self.mainAppViewController = [[MasterTableViewController alloc]initWithNibName:masterTable bundle:nil];
break;
case 2:
self.mainAppViewController = [[DetailViewController alloc]initWithNibName:detail bundle:nil];
break;
}
[_mainAppView addSubview:[_mainAppViewController view]];
[[_mainAppViewController view] setFrame:[_mainAppView bounds]];
[[_mainAppViewController view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// automatically run the master table view controller
NSInteger tag = 1;
[self changeViewController:tag];
}
Now, some of you may wondering, where is the rest of the code. I have ommited the boiler plate code for the core data below in the AppDelegage.m, since it is unchanged. I used binding to make my NSTableView to work and to display my records, so MasterTableViewController.h and .m files are empty, and same is true for the DetailViewController.h and .m file.
Important note - What i can't understand here: If I change the tag in 2 in the applicationDidFinishLaunching method, detail view is displayed normally, but if i switch it back on 1, and then double click on the row, "master" view (with the NSTableView) remains visible, and nothing happen (views are not swapped)
Anyone can help me to find out what is wrong with my code?
Regards, John
You apparently had a second instance of your AppDelegate class instantiated in the MasterTableViewController.xib file. There should be only one AppDelegate instance and that's the one in MainMenu.xib. So, it shouldn't be in MasterTableViewController.xib.
One of the instances was receiving the double-click action method from the table, but the other one was the one with the outlet to the main window.
You need(ed) to get rid of the second instance and find another way to access the app delegate from the MasterTableViewController.
I have a UIPageViewController which I setup in the viewDidLoad method of the RootViewController as follows:
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
The delegate pageViewControllerspineLocationForInterfaceOrientation is called successfully and I can set the spine accordingly.
However, I want to setup the PageViewController on a button click so I moved the code to the event handler of the button pressed event. Now the delegate is not called.
Any ideas how I can fix it?
It is some what complicated but can be achieved through the code below :
Step 1: Add below code to .h file of rootViewController.
#property (strong, nonatomic) IBOutlet UIButton *previousClick;
#property (strong, nonatomic) IBOutlet UIButton *nextClick;
Step 2: Connect them to the xib or storyboard which ever you use.
Step 3: Add two IBAction methods to .m file.
#pragma mark - IBAction Methods
- (IBAction)previousClick:(id)sender
{
[_modelController pageViewController:self.pageViewController viewControllerBeforeViewController:_dataViewController];
}
- (IBAction)nextClick:(id)sender
{
[_modelController pageViewController:self.pageViewController viewControllerAfterViewController:_dataViewController];
}
Step 4: You also need to put below lines too to .m file
#interface RootViewController ()
#property (readonly, strong, nonatomic) ModelController *modelController;
#property (readonly, strong, nonatomic) DataViewController *dataViewController;
#end
And synthesize them as below
#synthesize modelController = _modelController;
#synthesize dataViewController = _dataViewController;
Step 5: Last and final add below line to - (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation method.
_dataViewController = currentViewController;
after the currentViewController's alloc init call.
If you find that the added buttons are hidden by the pageViewController just bring them to the front using the code below in side the -viewDidLoad method
[self.view bringSubviewToFront:self.previousClick];
[self.view bringSubviewToFront:self.nextClick];
I am attempting to hide a NSButton that performs miniaturize when a different NSButton on the interface is clicked. My attempts thus far have been unsuccessful, this is what I have tried:
.h file:
#interface AppDelegate : NSObject <NSApplicationDelegate> {
IBOutlet NSWindow *window;
IBOutlet WebView *webView;
IBOutlet NSButton *doMinimize;
}
#property (assign) IBOutlet NSWindow *window;
#property (assign) IBOutlet NSButton *button;
#property (nonatomic, retain) IBOutlet WebView *webView;
.m file:
#implementation AppDelegate
#synthesize window;
#synthesize webView;
#synthesize doMinimize;
- (IBAction)toggleFullscreen:(id)sender
{
...
[doMinimize setEnabled:NO];
[doMinimize setTransparent:YES];
...
}
It appears that no matter in what action I try to disable and make the button transparent, it doesn't seem to respond to anything. Do I have to give the button it's own class to make this work? If so, how would I then be able to modify that button from an IBAction inside of a different class?
I apologize in advance if my question is silly, I'm relatively new to the world of Objective-C and am just now starting to get my feet wet.
Thanks in advance.
Have you tried -setHidden:?
[doMinimize setHidden:YES];