View controller not taking up entire window frame in Mac OSX project - objective-c

So I'm creating a mac OSX app and right now I have a main view controller set up to be the size of the window and a NSView subview on top of the view controller with the same frame size. However, this is the result I am getting: (I colored the NSView subview pinkish)
What I want is for the whole window to be taken up by the NSView subview (so the whole window should be pink). Here is my code thus far:
In AppDelegate.m:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
self.mainViewController = [[NSViewController alloc]
initWithNibName:Nil bundle:Nil];
self.mainViewController.view.frame = ((NSView *)self.window.contentView).bounds;
[self.window.contentView addSubview:self.mainViewController.view];
}
And then in my view controller:
-(void)loadView
{
[super loadView];
NSView *myView = [[NSView alloc] initWithFrame:self.view.frame];
CALayer *viewLayer = [CALayer layer];
[viewLayer setBackgroundColor:CGColorCreateGenericRGB(100.0, 0.0, 0.0, 0.4)];
[myView setWantsLayer:YES];
[myView setLayer:viewLayer];
[self.view addSubview:myView];
}
What am I doing wrong?

Instead of adding a subview to your view controller in your loadView: method, you should set the view of view controller here as:
-(void)loadView
{
.
.
.
// [self.view addSubview:myView]; //update this to
[self setView: myView];
}

Related

Lag / Delay on ModalViewController dismiss after loading an xib view over SKView

Imagine this scenario (some code below):
I have an SKView on a viewcontroller.
I load an xib view (external .xib file) over skview (xib view is a like small menu view that does not cover screen in full).
Then, I show a view controller modally from SKView's controller
When I dismiss this modal view controller, there is a lag on every second dismissal (so, i show it modally, dismiss, it is fine, then i repeat, there is delay, then repeat, works fine, then do again, there is delay ... and so on)
If I do not use SKView (if i just used UIView), that delay does not happen. It only happens when I use SKView.
What may be causing that? Here is simplified code that produces this problem:
#implementation NOZTestController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// button that loads xib view onto the current skview
UIButton *showxib = [[UIButton alloc] initWithFrame:CGRectMake(20, 80, 280, 30)];
[showxib setTitle:#"Add xib view here" forState:UIControlStateNormal];
[showxib addTarget:self action:#selector(showxibTapped) forControlEvents:UIControlEventTouchUpInside];
// button that loads a view controller programmatically
UIButton *showmodal = [[UIButton alloc] initWithFrame:CGRectMake(20, 120, 280, 30)];
[showmodal setTitle:#"Show modal" forState:UIControlStateNormal];
[showmodal addTarget:self action:#selector(showmodalTapped) forControlEvents:UIControlEventTouchUpInside];
self.view = [[SKView alloc] initWithFrame:self.view.frame];
SKView *v = (SKView *)self.view;
//UIView *v = self.view;
[v addSubview:showxib];
[v addSubview:showmodal];
}
- (void)showxibTapped
{
// displays the xib view
[NOZPlayAgainView presentOnView:self.view inRect:CGRectMake(20, 200, 280, 160) withDelegate:self];
}
- (void)showmodalTapped
{
// displays the modal window
UIViewController *vc = [[UIViewController alloc] init];
UIButton *dismiss = [[UIButton alloc] initWithFrame:CGRectMake(40, 40, 240, 40)];
[dismiss setTitle:#"Dismiss" forState:UIControlStateNormal];
[dismiss addTarget:self action:#selector(dismissModal) forControlEvents:UIControlEventTouchUpInside];
[vc.view addSubview:dismiss];
[self presentViewController:vc animated:YES completion:nil];
}
- (void)dismissModal
{
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
}
#end
It is caused by autolayout constraints on the xib view. To arrive to that conclusion, I created a simple view with a subview and added it to SKView. The problem I reported above happened only when I used auto layout constraints to place the subview. I don't know why this is happening but that is the reason for it.

How to fade out a subview to show a UIViewController's view loaded from a .nib

I have ViewController which is loaded from a .nib file. in the viewDidLoad method I create a subview and add it to the view hierarchy. How do I fade out that subview to show the view in .nib file?
(the subview is like a splash screen, which I want to fade out to show the view in the .nib, it's set up this way since it was easiest way for me.)
Here is some of my code (I tried to set a reference to the original view from the nib in the viewDidLoad but couldn't get it to work):
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"View did load");
//set reference to view in .nib here
UIView *currentView = self.view;
CGRect frame = [[UIScreen mainScreen] bounds];
splashView = [[splashView alloc] initWithFrame:frame];
[[self view] addSubview:splashView];
//transition did not work
[UIView transitionFromView:splashView toView:currentView duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve completion:^(BOOL finished) {
NSLog(#"transition finished");
}];
}
That code crashes. What am I doing wrong?
Try the following in place of your original code:
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"View did load");
CGRect frame = [[UIScreen mainScreen] bounds];
splashView = [[splashView alloc] initWithFrame:frame];
[[self view] addSubview:splashView];
[self.view bringSubviewToFront: splashView];
[UIView animateWithDuration: 2.0
delyay: 0.5 // omit if you don't need a delay
options: UIViewAnimationCurveEaseOut // check the documentation for other options
animations: ^{
splashView.alpha = 0;
}
completion: ^(BOOL finished) {
[splashView removeFromSuperView];
}];
I don't know if you're using ARC or not, or if you using storyboards or not!
If you're note using ARC, then memory management is wrong in this snippet.

view controller frame size in child controller

I am implementing UIViewcontroller containment. In the example below I set the frame size of the childcontrollers in the rootcontroller. The child view appears as the size I have set, however when I check on its bounds within container1 it reports a different size to the size I set.
Rootcontroller (container)
- (void)viewDidLoad
{
[super viewDidLoad];
self.containA = [[Container1 alloc]init];
self.containB = [[Container2 alloc]init];
self.containA.view.frame = CGRectMake(50, 50,50, 50);
self.containB.view.frame = CGRectMake(50, 50, 300, 300);
[self addChildViewController:self.containA];
[self addChildViewController:self.containB];
[self.view addSubview:self.containA.view];
Container1
-(void)viewDidLoad {
[super viewDidLoad];
UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
//[self.view addSubview:view];
self.view = view;
self.view.backgroundColor = [UIColor redColor];
[view release];
NSLog(#"view dims %f %f",self.view.bounds.size.width,self.view.bounds.size.height);
}
Console output from container 1
view dims 768.000000 1004.000000
I thought the issue was related to setting the view frame to UIScreen main screen]applicationFrame .So I removed all of this code so the uiview is created automatically. The issue still remains..
View frames are not actually useable in viewDidLoad; you should move all of your geometry-manipulating code into viewWillAppear. The system will clobber any changes you set in viewDidLoad between there and when it's about tom come on screen.

UIView in front of everything not rotating with screen?

I have this code:
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
imageView.image = [UIImage imageNamed:#"image.png"];
UIApplication *app = [UIApplication sharedApplication];
[app addSubViewOnFrontWindow:imageView];
...
- (void)addSubViewOnFrontWindow:(UIView *)view {
int count = [self.windows count];
UIWindow *w = [self.windows objectAtIndex:count - 1];
[w addSubview:view];
}
The problem is, when the app rotates, the view on the front doesn't rotate. It just stays in portrait.
How can I get this to rotate normally with the rest of the device?
I haven't tried this, but UIWindow has a property rootViewController
The root view controller for the window.
#property(nonatomic, retain) UIViewController *rootViewController
Discussion
The root view controller provides the content view of the
window. Assigning a view controller to this property (either
programmatically or using Interface Builder) installs the view
controller’s view as the content view of the window. If the window has
an existing view hierarchy, the old views are removed before the new
ones are installed.
The default value of this property is nil.
Availability
Available in iOS 4.0 and later.
Declared In
UIWindow.h
As you should be providing this root view controller you should be able to add it to the rootViewContoller's view, and handle aout rotation correctly.
another solution could be, that you swap the windo with a custom one while presenting your view, with another view controller. this trick in action you can see in the implementation of TSAlertView.
- (void) show
{
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:[NSDate date]];
TSAlertViewController* avc = [[[TSAlertViewController alloc] init] autorelease];
avc.view.backgroundColor = [UIColor clearColor];
// $important - the window is released only when the user clicks an alert view button
TSAlertOverlayWindow* ow = [[TSAlertOverlayWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];
ow.alpha = 0.0;
ow.backgroundColor = [UIColor clearColor];
ow.rootViewController = avc;
[ow makeKeyAndVisible];
// fade in the window
[UIView animateWithDuration: 0.2 animations: ^{
ow.alpha = 1;
}];
// add and pulse the alertview
// add the alertview
[avc.view addSubview: self];
[self sizeToFit];
self.center = CGPointMake( CGRectGetMidX( avc.view.bounds ), CGRectGetMidY( avc.view.bounds ) );;
self.frame = CGRectIntegral( self.frame );
[self pulse];
if ( self.style == TSAlertViewStyleInput )
{
[self layoutSubviews];
[self.inputTextField becomeFirstResponder];
}
}
with
#interface TSAlertOverlayWindow : UIWindow
{
}
#property (nonatomic,retain) UIWindow* oldKeyWindow;
#end
#implementation TSAlertOverlayWindow
#synthesize oldKeyWindow;
- (void) makeKeyAndVisible
{
self.oldKeyWindow = [[UIApplication sharedApplication] keyWindow];
self.windowLevel = UIWindowLevelAlert;
[super makeKeyAndVisible];
}
- (void) resignKeyWindow
{
[super resignKeyWindow];
[self.oldKeyWindow makeKeyWindow];
}
//
#end
add a new window, with new rootviewController, and subscribe it to
[[NSNotificationCenter defaultCenter] addObserver:(id) selector:(SEL) name:UIDeviceOrientationDidChangeNotification object:nil];
Windows don't autorotate. Ever. You should be adding this imageView to a UIViewController's view as the UIViewController has built in autorotation.
If you want to use a UIWindow to hold all your views, you will need to write your own transform code to handle rotations.

How to position a UIToolbar in a UIWebView

I've a sample project, where I have created a custom UIWebView named WebView. They are added to the view in a UIViewController. Two WebView's are initialized in the viewDidLoad and added to an array list. The first one is added as subview på self.view. The Storyboard contains a UIBarButton, and when this is tapped, the second WebView is added as subview to the self.view.
- (void)viewDidLoad
{
[super viewDidLoad];
WebView *webView1 = [[WebView alloc] initWithFrame:self.view.bounds];
WebView *webView2 = [[WebView alloc] initWithFrame:self.view.bounds];
self.webViews = [NSArray arrayWithObjects: webView1, webView2, nil];
UIWebView *webView = [self.webViews objectAtIndex:0];
[self.view addSubview:webView];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://m.google.com/"]]];
}
Here is the implementation of the WebView where a toolbar is added to the bottom (-50px) of the view:
#implementation WebView
- (void) initToolbar {
UIToolbar *toolbar = [UIToolbar new];
toolbar.barStyle = UIBarStyleBlackTranslucent;
toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
[toolbar sizeToFit];
toolbar.frame = CGRectMake(0, self.frame.size.height-80, 320, 30);
[self addSubview:toolbar];
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self initToolbar];
}
return self;
}
#end
The problem is, that the toolbar does not have the same position in the two views (they could be positioned like the first one). Why are they not positioned equally?
You can download the small sample project here:
http://uploads.demaweb.dk/UIWebView.zip
My notes: As mentioned, the two WebView's are currently initialized in the viewDidLoad. If I instead wait and first initialize then when I need them, it seems to work as expected.
The thing here is that self.frame.size.height on viewDidLoad is not the same when you initialize it via the button click. If you add the UIWebView directly in viewDidLoad, the UINavigationBar of your UINavigationController is not loaded yet and the frame of self.view is 'perceived' to be (not really, because it is) larger.
This explains the difference of 40.0 (?) points.
One possible solution to this problematic behaviour is to initialize and add (at least the first) instance of UIWebView in the viewWillAppear:animated method. (UIViewController does already implement this method)