iOS unable to autoresize subviews when device rotation - iphone

I tried several solutions found on other posts but still having problems to autoresize subviews when device rotation. My layout (IB) has three views and only apply resize to current view. If then, after rotating device, view is shown, was not resized and remains at previous dimensions. I set autoresize subviews and its mask... What am I doing wrong or missing? any help would be appreciated, thank you!
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setAutoresizesSubviews:YES];
[self.view setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[vistaSocial setAutoresizesSubviews:YES];
[vistaSocial setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[vistaB setAutoresizesSubviews:YES];
[vistaB setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];

I think you are not using a proper resizing properties on xib file. As per my understanding, you must have added 2-3 views on current controller; but auto-resizing is getting wrong somewhere. Try one by one and with a correct set.
You can share any screen shot for better understanding, if i am predicting it wrong.

You can set Autoresize property with the help of Nib file. Can you please check once you set it properly from NIB file?

For a given view to adjust its size upon device rotation, it is its superview that needs to have its autoresizesSubviews property set to YES. (It is not clear from your code fragment what your view hierarchy is.) Try changing
[vistaB setAutoresizesSubviews:YES];
to
[vistaB.superview setAutoresizesSubviews:YES];

Related

Changing frame of UIView's CALayer (self.view.layer.frame = ...) appears to have no effect

I'm sure I'm missing something basic here. I'm trying out the CALayers 'hello world' code from:
http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial
Doing the very first example. New single view project in xcode 4.2. No change to the nib/storyboard. Import QuartzCore. Add the following code to ViewDidLoad in the ViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.layer.backgroundColor = [UIColor blueColor].CGColor;
self.view.layer.cornerRadius = 30.0;
self.view.layer.frame = CGRectMake(20, 20, 20, 20);
}
I run this (ipad 2 or ipad simulator) and get a full screen blue rectangle with rounded corners. What I hoped to get was a 20x20 blue rectangle offset by 20/20.
I'm clearly getting control over the views layer (as shown by the color and rounded corners). However, adjusting the frame seems to have no impact. I've NSLog'ed the frame before/after setting it, and it has changed. Is the frame of the root layer locked to the uiview frame?
I don't have a strong reason to change the views layers frame, I'm just trying to reason through what is going on. Hopefully this is an easy question...
Thanks!
Paul
Actually, the previous answer (you can't set uiview.layer.frame as it always fills the uiview) is close, but not quite complete. After reading the answer, I registered for the original site and to comment that the tutorial had issues. In doing so, I found that there were already comments that I hadn't seen in my first pass that addressed this. Using those, I started doing some testing.
The bottom line, if you move the self.view.layer.frame setting code from viewDidLoad to viewWillAppear, it works fine. That means that you can change the frame of the root layer of a view. However, if you do it in viewDidLoad it will be undone later.
However, the previous answer is still pretty close. I NSLog'ed the frame of the root layer and the frame of the view. Changing the root layer frame changes the view frame. So, the answer that the view.layer.frame always fills the view.frame is correct. However, setting the layer frame resets the view frame to match. (I'm guessing that uiview.frame property simply returns uiview.layer.frame...)
So, at some point in time between 2010 and today, something in the environment changed. Specifically, after viewDidLoad and before viewWillAppear the uiview/layer frame appears to be reset to the nib specified value. This overrides any changes in viewDidLoad. Changes made in viewWillAppear appear to stick.
Robin's answer got me on the right track, but I wanted to spell out the full answer.
The tutorial is wrong. Setting the frame of the view's main layer has no effect. The main layer is 'special' and will always fill the view's bounds. What you need to do is create a sublayer of the main layer like this:
- (void)viewDidLoad
{
[super viewDidLoad];
CALayer *newLayer = [[CALayer alloc] init];
newLayer.backgroundColor = [UIColor orangeColor].CGColor;
newLayer.cornerRadius = 20.0;
newLayer.frame = CGRectMake(100.0f, 100.0f, 200.0f, 200.0f);
[self.view.layer addSublayer:newLayer];
[newLayer release]; // Assuming you're not using ARC
}
Also, in your code a layer with width 20pt and height 20pt is too small to have rounded corners of 30pt anyway.

UIView addsubview after orientation change: Tell view to resize

I have a UIView as a XIB in Portrait mode.
This view is added programmatically to the viewcontroller like this:
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"InputView" owner:self options:nil];
InputView *inputView = (InputView*)[nibObjects objectAtIndex:0];
[self.view addSubview:inputView];
This view has autoresizing masks set up properly and rotates fine when the orientation changes from Portrait to landscape.
However, if the orientation is already landscape and I create the view after the orientation change, it has its initial portrait orientation.
Is there a way to tell the view to initialize or resize itself to portrait by using its masks?
Thanks in advance for any reply!
EDIT:
Using the suggestions of occulus and Inder Kumar Rathore (thanks guys!), I altered the code to this:
InputView *inputView = (InputView*)[nibObjects objectAtIndex:0];
[self.view addSubview:inputView];
[self.view setNeedsLayout];
[self.view layoutSubviews];
[self.view layoutIfNeeded];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
[self shouldAutorotateToInterfaceOrientation:orientation];
Unfortunately, there is no change at all.
I think I found someone asking the same question:
When adding a sub view the view does not resize if the app is in landscape mode
The answer identifies the problem correctly, but is not very encouraging...
Sure, I could create two nibs or resize the frame, but this seems so contrary to the idea of auto-resizing.
I find it hard to believe that there is no way to tell a nib after awakening and adding it to a view to use its autoresize features...something that works flawless when the device rotates.
EDIT 2:
The solution of idz works:
InputView *inputView = (InputView*)[nibObjects objectAtIndex:0];
[self.view addSubview:inputView];
inputView.frame = self.view.bounds;
[inputView show];
Thanks!
Often a NIB/XIB file contains a UIViewController that takes care of all of this. In this case, since their is no view controller (in the NIB/XIB) you need to take over its post-load duties.
Calling layoutSubviews directly, or indirectly via setNeedsLayout or layoutIfNeeded won't do you much good because the default implementation does nothing.
Assuming you want input view to fill the bounds of self.view you do the following:
InputView *inputView = (InputView*)[nibObjects objectAtIndex:0];
[self.view addSubview:inputView];
inputView.frame = self.view.bounds;
[inputView show];
All the resize masks of the sub-views must be correctly set for this to work and, obviously, if you don't want to fill the full bounds you may want to adjust the frame.
[self.view addSubview:viewSpinner];
viewSpinner.frame = self.view.frame;
[viewSpinner setNeedsLayout];
This works for me (Y)
I don't know if you still have this issue.
Let's say you have the following architecture:
window
subviewcontroller
(you implemented shouldautorotate correct to answering the wanted orientations)
Into this subviewcontroller you want to add the views of new UIViewControllers by just calling the addSubview function.
Instead of implementing the bounds manipulation in shouldautorotate, you should implement it in
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
self.newUIViewController.view.frame = self.view.bounds;
}
didRotateFromInterface... is called after shouldRotate. In this function the bounds are already setup correctly.
This way you don't need so much manipulation by code.
See this related question:
When do autoresizing masks take effect in iOS?
So after loading your new view from the nib, and adding as a subview to self.view, try calling setNeedsLayout.

frequent bug in UI (tabbar pushed from navigation)

I have encountered this bug several times. I have a application with a navigation controller (navbar hidden). when a button is "pressed" i want to push another view with a tabbarviewcontroller. When the new view is pushed, it's 20 pixels lower than it should (and part of the tabbar is not visible).
If I enter modal-view controller from the tabbarviewcontroller and then i dismiss it, the tabbarviewcontroller is shown properly.
I put the status bar in every view to be unspecified (thought that was the problem) and i un-checked the autoresize subviews from each view.
in your code use bounds property instead of application frame . in my it worked hope to work in case too.......:)
This sounds like it might be related to a known NIB/XIB file bug (for more information see: http://forums.bignerdranch.com/viewtopic.php?f=51&t=125)
As the linked forum topic suggests, for a workaround simply use the following:
- (void)viewDidLoad {
[super viewDidLoad];
CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
[[self view] setFrame:appFrame];
}
thank you for your answers. i did it somehow, playing with the tabbar's frame a bit.
[self.tabBarController.view setFrame:CGRectMake(0, 0, 320, 460)];
[self.view addSubview:tabBarController.view];
[self.view bringSubviewToFront:tabBarController.view];
i remember trying this a while ago and not working. now it did.
also, medling with bounds helped a bit.

UIView autoresizingmask not working for me

I have my app set up so that auto-rotate works. Things like tableviewcontrollers and tabbarcontrollers automatically resize them selves without the need for me to write any code. However I need my webview etc. to resize when the device is turned to landscape. I set:
webView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
but when I rotate the device it does not resize. I am implementing this incorrectly?
I think I finally figured this out. It seems that the root view of a NIB file does not allow you to specify flexible width and flexible height for the autoresizing mask in interface builder (at least not as of 3.2). Take a look. Putting the following code in your viewDidLoad seems to fix the problem:
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
I did it after the super call.
I implement the following in my view controller:
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
[self.webView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
}
Seems to work well.

iPhone OS: Tap status bar to scroll to top doesn't work after remove/add back

Using this method to hide the status bar:
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:YES];
When setting "hidden" back to NO, the tap-to-scroll-to-top (in UIWebView, UITableView, whatever) doesn't work any more, and requires a restart of the app to get the functionality back.
Is this a bug (I filed a rdar anyhow) or have I missed a step? Should I perhaps expect this behavior since the statusBar "loses touch" somehow with the respective view?
You could try setting the ScrollsToTop property to true again after re-showing it:
[currentView setScrollsToTop:YES];
If that's not working, are you definitely only showing one view? If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored...
In iOS 5.0 you can access the scrollview property of the UIWebView
webView.scrollView.scrollsToTop = YES;
The following fix by Alex worked for me. Thanks!
((UIScrollView *)[[webView subviews] objectAtIndex:0]).scrollsToTop = NO;
Being in a hurry this fix worked great, however given more time I might've subclassed the UIWebView and accessed the protected UIScrollView member directly.
The worry I have with Alex' method is that it assumes that UIScrollView is at index zero of the subviews (encapsulation allows private members to change). Which suggests another solution still:
for (UIView* v in [webView subviews])
{
if ([v isKindOfClass:[UIScrollView class]])
{
(UIScrollView *)v.scrollsToTop = NO;
}
}
I was having a similar problem where the scroll-to-top functionality was lost. Turns out this will only work when you have only one active view at a time (within the same scroll view). In my case I had a table view and another view which would fade in/out. Adding a removeFromSuperview at the end of the animation did the trick.
The answer was in the UIScrollView.h file comments:
/*
this is for the scroll to top gesture. by default, a single scroll visible scroll view with this flag set will get the call. if there is more than one visible with this
flag set or the delegeat method returns NO, the view isn't scrolled
*/
#property(nonatomic) BOOL scrollsToTop; // default is YES. if set, special gesture will scroll to top of view after consulting delegate
You can use the following code to have the UIWebView ignore scrollToTop without the extra UIScrollView:
((UIScrollView *)[[webView valueForKey:#"_internal"] valueForKey:#"scroller"]).scrollsToTop = NO;
I had a similar problem after playing a Youtube video within my app. scrollsToTop was still set to YES but tapping the status bar had no effect.
I finally realised that my app window was no longer the key window. After adding the following line to a UIWindow subclass (which I already had for other reasons) everything worked as it should again:
if (![self isKeyWindow]) [self makeKeyWindow];
I just ran across a similar behavior in the app I'm currently working on. In its case, if you load a YouTube video from within a UIWebView, scroll to top stops working for the rest of the application's life cycle. I kind of assume this might happen after loading the movie player as well, but haven't confirmed. That functionality has been around a lot longer and probably has fewer bugs.
When there are multiple scrollview, you can also set scrollUpToTop to NO for the others scrollview. cf:
setScrollsToTop with multiple UIScrollView classes and/or subclasses(UITableView)
I want to add my case, I add an UIWebView on an UIScrollView, as h4xxr had answered on the top:
If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored
So, I get a simply way to make it work on webView: just set the scrollView·s scrollsToTop property false.
And when tap the status bar, it won`t got intercepted by the scrollView, and the webView scrolls to the top!
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.frame = self.view.bounds;
scrollView.scrollsToTop = false; //igore scrollView`s scrollsToTop
[self.view addSubview:scrollView];
UIWebView *webView = [[UIWebView alloc] init];
webView.frame = scrollView.bounds;
[scrollView addSubview:webView];