In my app I add a view loaded from XIB with UIViewAutosizingMaskFlexibleWidth and have the desired result only in one of two cases:
Adding subview on portrait, and rotating to landscape, resizes the subview correctly;
Adding subview on landscape do not cause the subview to resize its width the way it does when rotating;
Here is the code:
viewMenuList = [[MenuListController alloc] initWithNibName:#"MenuListController" bundle:[NSBundle mainBundle]];
viewMenuList.view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.view.autoresizesSubviews = YES;
[self.view addSubview:viewMenuList.view];
[self.view sendSubviewToBack:viewMenuList.view];
[viewMenuList.view setNeedsLayout];
[viewMenuList.view setNeedsDisplay];
NSLog(#"frame do menu links view %f, %f, %f, %f", self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
NSLog(#"frame do menu list view %f, %f, %f, %f", viewMenuList.view.frame.origin.x, viewMenuList.view.frame.origin.y, viewMenuList.view.frame.size.width, viewMenuList.view.frame.size.height);
The output in the console is:
2010-12-07 16:34:22.552 SlideShow_iPad[19352:207] frame do menu links view 0.000000, 0.000000, 1030.000000, 111.000000
2010-12-07 16:34:22.596 SlideShow_iPad[19352:207] frame do menu list view 0.000000, 0.000000, 768.000000, 109.000000
The last line should display an width of 1030, shouldnt it? It does resize to 1030 after rotating to portrait and going back to landscape.
The strangest thing is that I do use the same technic in the superview and worked.
You shouldn't mix both Interface Builder and Objective-C code to handle resizing. Remove autoresizingMask and autoresizesSubviews from code and do both only in Interface Builder. You might have conflicting defines now.
autoresizingMark: command-3 to view size properties. Check "Autosizing" part, the animation shows pretty nicely how your resizing will look.
autoresizesSubviews: command-1 to view drawing properties. There's a checkbox for this.
Related
I have a subclassed UINavigationBar where I'm overriding drawRect to provide a png with transparency as a background. Every thing works as expected, save for a 1 pixel space at the top of the bar (I can see the underlying map moving in the space).
screen shot
Only thing I was able to find is this question which sounds like my problem but I don't know what to make of the explanation: Empty space of 1 pixel above UINavigationBar
I have verified that the PNG file does not have 1 pixel of transparency at the top of the image.
Overriding in subclassed UINavigationBar:
- (void)drawRect:(CGRect)rect {
[_bg drawInRect:CGRectMake(0, 0, _bg.size.width, _bg.size.height)];
// showing correct bounds - drawRect: 0.000000, 0.000000, 320.000000, 85.000000
NSLog(#"drawRect: %f, %f, %f, %f", rect.origin.x,
rect.origin.y,
rect.size.width,
rect.size.height);
}
- (CGSize)sizeThatFits:(CGSize)size {
CGRect frame = [[UIScreen mainScreen] applicationFrame];
CGSize sz = CGSizeMake(frame.size.width, _bg.size.height);
NSLog(#"sizefits");
return sz;
}
Thanks for any help!
I had the same problem with my custom nav bar, although I was using UIAppearance proxies to set a custom background image instead of overriding drawRect:. This was my quick fix, in viewWillAppear: on the root view controller:
// Make sure nav bar is flush with status bar (iOS 5 iPhone portrait somehow gives status bar height 20 and nav bar y 20.5, so we miss a pixel).
CGRect navBarFrame = self.navigationController.navigationBar.frame;
navBarFrame.origin.y = [UIApplication sharedApplication].statusBarFrame.size.height;
self.navigationController.navigationBar.frame = navBarFrame;
I'm trying to layout several custom views in a landscape iPad application (made landscape by deleting all but one interface mention in the plist). However, my code currently doesn't work as expected;
- (void)viewDidLoad {
[super viewDidLoad];
LeftTableViewController *lvc = [[LeftTableViewController alloc] initWithNibName:#"LeftTableViewController" bundle:nil];
// Resize this view controller appropriately
lvc.view.frame = CGRectMake(0, 0, 224, 768);
[[self view] addSubview:lvc.view];
ReaderViewController *rvc = [[ReaderViewController alloc] initWithNibName:nil bundle:nil];
// Resize this view controller appropriately
rvc.view.frame = CGRectMake(224, 0, 800, 768);
[[self view] addSubview:rvc.view];</code>
I expected the code above to give me the LeftTableViewController entirely to the left. This appears to work, but I had to remove all the size markers from the nib to get it there. The ReaderViewController should take up the remaining space, but it only takes up about half of the space left. This image illustrates this (the ReaderViewController is the green space, while the application is the purple space).
http://i52.tinypic.com/z7d2.png
I seem to be misunderstanding something crucial about frames and bounds in landscape mode. What coordinates for the frame or bounds should I set for a view to appear as expected and why?
Coordinates are same for both landscape, portrait modes. Portrait is 0,0 (left, top) and 768,1024 (width, height) and 0,0 (left, top) and 1024,768 (width, height) for landscape.
It's quite hard to answer, because we don't see the whole code and your XIB file. You have wrong autoresizing mask probably.
P.S. 768 is not correct height, because you have status bar visible, which has 20 pixels.
I've managed to manually detect rotation and set my own rotation effects between two UIViewControllers. When in the first, rotating to landscape prompts the second to be pushed on with a manual animation. The status bar moves to the correct orientation. However, the view loaded by the second UIViewController is not in the position I expected it. Instead there is margin on the left where the status bar previously was and margin/space at the bottom that I was expecting to be filled by the view.
(Click to enlarge. The orange box is simply to reference where 0,0 is in the rotated UIView, CustomView)
The code I'm using in my view controller to do the rotation is:
-(void)loadView {
CustomView *customView = [[CustomView alloc] initWithFrame:CGRectMake(0, 20, 480, 300)];
self.view = customView;
CGAffineTransform rotate = CGAffineTransformMakeRotation(degreesToRadian(90));
[self.view setTransform:rotate];
[customView release];
}
Any help would be much appreciated!
EDIT Managed to solve after a variety of trial and error approaches - answer provided below. Perhaps there's a more elegant/obvious solution though - if so feel free to provide!
try these on the viewcontrollers. Solved the 20 pixel(status bar height) clip issue when I was getting fullscreen subviews to show up.
[viewcontroller1.view setCenter:CGPointMake(viewcontroller1.view.center.x, viewcontroller1.view.center.y-20)];
and/or
[viewcontroller2.view setCenter:CGPointMake(viewcontroller2.view.center.x-20, viewcontroller2.view.center.y)];
I managed to solve this by setting the View's bounds after the transformation:
self.view.bounds = CGRectMake(20, -20, 480, 300);
Edit 2: When I start the app without the status bar on top everything behaves as planned. With the status bar I couldn't get the views to act as I wanted. It looks as if the UINavigationController keeps resizing the content view by subtracting the 20 pixels of the status bar. I don't know.
I created a simple UINavigationController-based application. The root view in this navigation controller is a UITableView. At a certain time I want to slide in a 80 pixel high view from the bottom. The whole view on the top (the one that is controlled by the UINavigationController) should resize and get 80 pixel smaller to make room for the new bottom view.
This is basically the code I use to repositioning the views:
-(void)showTeaser {
float adHeight = 80;
[adView setFrame:CGRectMake(0.0,self.navigationController.view.bounds.size.height, 320.0, 80.0)];
[[[UIApplication sharedApplication] keyWindow] addSubview:adView];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[adView setAlpha:1.0];
[adView setFrame:CGRectMake(0.0,self.navigationController.view.bounds.size.height-adHeight, 320.0, 80.0)];
[self.navigationController.view setFrame:CGRectMake(0.0,0.0, 320.0, self.navigationController.view.bounds.size.height-adHeight)];
[self.view setFrame:CGRectMake(0.0, 0, 320.0, self.view.bounds.size.height-adHeight)];
[UIView commitAnimations]; }
I lowered the Navigationbar's alpha, set the UITableviewController's view to red. The new view is purple.
This is what happens. First screenshot initial state. Everything is looking normal. Second screenshot shows state after changing the frames. The view of the UITableviewController is always pushed 20 pixel under the Navigationbar. Also, if I try to add more views to the keywindow, they always end up 20 pixel higher than I expect. It almost looks like the keywindow (minus the navigation bar) is pushed up 20 pixel.
Edit 1: No matter to what size I resize the view, it's always 20 pixel.
Do I make a mistake by adding views to the keywindow at all? Shouldn't I do this?
alt text http://www.hans-schneider.de/iphone-seo/1.png alt text http://www.hans-schneider.de/iphone-seo/2.png
To solve this, I made the view of the UINavigationController a subview of a UIView, and manually set the bounds of the view for the `UINavigationController'.
//outerView is a UIView defined in the interface
outerView = [[UIView alloc] initWithFrame:CGRectMake( 0.0, 0.0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);];
//mainNavigationController is a UINavigationController defined in the interface
//rootViewController is a UIViewController (or inherited class) defined in the interface and instanced before this code
mainNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
//set the frame for the view of the navigation controller - 20 is due to the status bar
mainNavigationController.view.frame = CGRectMake( 0.0, 20.0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 20);
Then later, when I go to resize, I resize the parent 'UIView' rather than the 'UINavigationController' view.
//change the outer view's frame to resize everything
//adHeight is a float defined earlier
outerView.frame = CGRectMake( 0.0, 20.0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 20 - adHeight);
This works well in an animation sequence.
Edit 2011-05-12: I updated the outerView frame to fill the screen. This must be set to allow for touch events.
Have you tried using the transform property of your tableview instead of manually changing it's frame? It may work out better, since the frame depends on the origin, and you only want to change it's size.
I'm developing an app in objective-c and in that app set the navigationBar to translucent(through IB). But the problem is that the view displayed behind the navigation bar.
Anybody else tried working with translucent navigation bars?
regards
Jayaraj
The [navigationController view] automatically resizes to "underlap" translucent navigation bars as of OS 3.0
You can simply add 44 pixels to the y value of the origin property to overcome this.
You can use 44 if you know you're in portrait (not landscape, in which the height of the navBar is less than 44)
You can also do:
// applicationFrame subtracts the height of the statusBar if it's visible.
// bounds doesn't take into account the statusBar.
CGRect navFrame = [[UIScreen mainScreen] applicationFrame];
NSLog(#"navFrame: %f x %f", navFrame.size.width, navFrame.size.height);
navFrame.size.height -= self.navigationController.navigationBar.frame.size.height;
NSLog(#"navFrame: %f x %f", navFrame.size.width, navFrame.size.height);
UIImageView *imageView = [[UIImageView alloc] initWithFrame:navFrame];
NSLog(#"imageView: %#", imageView);
I learned this from reading three20's source code. You can find it on github.com
Matt