I have UIActivityIndicatorView centered horizontally in a XIB.
In iOS 4 (Simulator), the indicator defaults to Large White (the color property being introduced in iOS 5), which is fine. The weird part is that it is also offset.
My initial assumption was that something was wrong with the XIB (or something to that effect). However, in iOS 5 (Simulator, iPhone 4), it works perfectly.
Seeing as how the only thing changed from iOS 4 to iOS 5 regarding UIActivityIndicatorViews was the addition of the color property, I'm stumped. I'm aware that there's probably nowhere near enough information here to deduce the exact problem. I'm more concerned about where to start debugging, and welcome any suggestions as to what further information I could supply.
Further Information:
The iPad loads the indicator in a reliable position, only changing colors between iOS 4 and iOS 5.
I have two static origin points (portPoint = (x, y); landPoint = (w, z);), that I manually set on rotation. When the app loads, the indicator's origin is (correctly) portPoint (which I've verified via NSLog), despite being visually misaligned. When I rotate to landscape, the origin correctly (visually and data-wise) sets to landPoint. When I rotate back, the origin correctly (visually and data-wise) sets to portPoint, thus resolving the issue.
You're right that w/o seeing your code I can't tell if anything else is going on but centering a view within a superview and maintaining that when the device rotates is fairly simple. Try this:
Make sure the autoResizingMask of the UIActivityIndicatorView is set to UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin
Position the activity indicator in the center of its superview, either in the XIB file or in viewDidLoad
Don't change the frame of the activity indicator on rotation, it should stay centered automatically
If the above doesn't fix it, post some code along with the autoResizingMask and contentMode values for relevant views.
It sure looks like its positioned as if the device were in landscape. Check to see that you reposition it properly when the view size or orientation changes.
Ideas:
1/ Your view (activity indicator superview) is bigger than your display (bad autoresizing mask? bad values in xib plist?) or it has bad position inside its superview.
2/ Autoresizing masks are not set correctly. For the activity indicator it should be
(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin)
To debug this, try to put logging into viewDidAppear. Get the center (CGPoint) of your activity indicator and use UIView methods to convert it to your top view coordinates (e.g. [UIView convertPoint:fromView:]). This position should be the same as the one you see on the screen.
If it's not, there is some bigger problem, possibly connected with animation states.
Otherwise you should be able to find the view which translates your activity indicator to this weird position. Log the frames of all views in your hierarchy.
Check that you log the information at the right place and you don't change view positions after the logging.
Related
Currently, here's what's happening. If I'm in portrait mode, and I present a new modalViewController, and then rotate to landscape, autoResizing works perfectly and everything looks great. However, if I'm in landscape, and I present a new modalViewController, autoResizing does not work and everything looks funky. Can anyone think of any possible ideas as to why this could be happening? I'm desperate I've tried everything.
Maybe a way to fix this would be to figure out what code gets called by the system when I'm in portrait and I go landscape. Maybe I can call that exact code if my modalView is presented in landscape. I've tried layoutIfNeeded and setNeedsDisplay but they don't do anything. I've also tried setting the contentMode to redraw-doesn't help.
I have this in my viewDidLoad for the modal view
if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
{
NSLog(#"is landscape, width:%f", self.view.frame.size.width);
}
and this outputs 320, even though I'm in landscape, when it should be 480.
UIViewAutoResizingMasks are what we refer to as 'struts' and 'springs'. Consider this: you have a large square with a small square inside. In order for that square to stay perfectly centered, you must set a fixed width from each inside edge of the large square, so as to constrain it. These are struts.
Springs, on the other hand, work more like a UIView does during rotation. Let's say our view must stay on the bottom of the screen, aligned in the center. We want to keep it's Top spring flexible so that when the view rotates from 460 px to 320 px, it keeps it's same position relative to the screen's now changed dimensions.
Keeping this in mind, when a view is loaded in portrait (as all UIViewControllers are), but the actual orientation is landscape, it's possible that the view will get 'confused' and maintain a sort of messy hybrid orientation type view. If you absolutely must (and I cannot stress how last resort-ish this is) force an orientation change beforehand, use iOS 5.x's +attemptRotationToDeviceOrientarion
In my app all my controls are created in code. I have not used IB for controls. now i want to rotate the view to landscape mode. I know I have to use the shouldAutorotate method for this purpose.
But since I have not used IB, how can I resize the controls when they are in landscape mode? How can I position them correctly using code only?
In most cases you can get views to resize themselves appropriately just by setting their autoresizingMask property to some combination of:
UIViewAutoresizingFlexibleLeftMargin
UIViewAutoresizingFlexibleRightMargin
UIViewAutoresizingFlexibleTopMargin
UIViewAutoresizingFlexibleBottomMargin
UIViewAutoresizingFlexibleWidth
UIViewAutoresizingFlexibleHeight
For example, let's say you want a view's width to increase when you rotate it to landscape, you want it to maintain the same margins relative to the top, left, and right sides of the screen, and you want its height to remain the same. This means that out of the six attributes above, only the width and bottom margin should be flexible. The other four attributes are fixed. So you would do:
yourView.autoresizingMask = UIViewAutoResizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
In those rare cases when you can't get the views to behave appropriately using their autoresizingMask property, you can wrap them in a custom view and override that view's layoutSubviews method. This method gets called when the view's frame changes due to autorotation, so you can check [[UIApplication sharedApplication] statusBarOrientation] and update the frames of your subviews manually.
You position them correctly using code the same way you likely positioned them in the original orientation, for example by setting their frame.
As for where in code to do this, check out the various orientation change methods of UIViewController that will be called when the device orientation changes. You could, for example, move/resize the controls in the view within willAnimateRotationToInterfaceOrientation:duration:.
I'm having a nightmare with the rotation on iPad. I've searched all over the place for some tutorials, but nothing seems to really be for what I want. (Possibly not searching for the right thing?!)
I have a portrait view by default which is an image and a button inside the view. When I rotate, I detect this can work out if it's landscape. I then try to set the frame size of the uiview to fit nicely on the screen.
If I let it autoresize, it simply stretches and fills the screen. This I don't want.
but the trouble is, when I resize, the button gets resized too, but not in the same ratio as the image.
My question is: What's the best way to resize the view. I wanted to simply reduce the uiview by say 60% and it resizes EVERYTHING in that view with the same 60%. The only way I see this is working at the moment is to create two views... but that's twice the work and maintenance!
I've tried messing with the autosizing arrows in Interface builder, but that again seems to screw things up more!
I'm completely lost here!! Thanks for any info
The problem you have there is that the view is automatically resized to the screen ratio. On an iPad in Portrait Orientation the screen size is 1024x768. After the rotation to Landscape the origin rotates too and your screen content is skewed or stretched to 768x1024.
What you need to do is to override the
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
message of the UIViewController of the view which rotates. This message is called within the animation block of the rotation. You just set the framesize of your subviews (the button) to whatever is best for you. Once i had a problem with rotating an OpenGL view. The content of the view was stretched when rotating to landscape. Since it is not possible to alter any OpenGL matrices within the animation block the only solution i found was to make the view quadratic and to set the origin behind the bounds of the screen (in -x direction). You have to override the message also to reset the origin above the screen (in -y direction) bounds in landscape mode, to keep the viewport in the middle of the screen. That way the view kept its ratio. Whatever solution is best for you, overriding this message should work out.
Have you tried disabling the autoresizesSubviews property on your UIView? It should prevent any size changes on the subviews when you resize your view.
I'm learning to develop for iPhone (programmatically, I don't like IB). I only use IB for the frames of things, so I design in IB but only use it to check each control's frame. Something I've gotten very confused about is the frame of a UIView. First of all, if you do not implement loadView in a view controller, it automatically creates an empty UIView (and I've noticed that its black) and assigns that to self.view, correct? What about the frame? does it automatically figure out what the frame should be? I mean, it needs to be different depending on the if there is a status bar, if there's a tab bar, a toolbar, the orientation. In my tab bar app, it seems no matter what I set frame of my uiview is, it still looks fine. And also, the frames for UIView seem messed up in IB. Like the y value of a UIView taking up the whole window (except status bar) is 0, when it should be 20, because the status bar takes up the top 20 pixels. And in IB a view in a tab bar controller has a y value of 411, even though it begins right under the status bar. And whenever I NSLog a frame (the four numbers, view.frame.origin.x, view.frame... etc.) the x, y, width and height are always 0.. Can someone who understands it please explain it to me? Thanks!!
Ok, this is weird... This:
CGRect test = CGRectMake(0, 20, 320, 460);
NSLog(#"%d %d %d %d", test.origin.x, test.origin.y, CGRectGetWidth(test), CGRectGetHeight(test));
gives output:
0 0 0 1077149696
??? What's with that?
First thing you should note is that CGRect's origin and size members use float, so in your NSLog statement you need to use %f, not %d. So for example,
NSLog(#"%f %f %f %f", test.origin.x, test.origin.y, test.size.width, test.size.height);
Pixel sizes are floats because on the desktop you need precise math when doing scaling and want to support proportional sizing. If you stick to integers and the window size is expanded by, say 1.2x, integer round-off will throw things out of line. They kept the same thing on the iPhone because you can have subviews that get auto-sized and floats offer more control over size and position.
As for the view positions, if you go into IB and select a view and check the "View Attributes" inspector you'll see one of the options is to show "Simulated Interface Elements." By default it has the Status Bar enabled (with Gray) and it allows for its height in the interface. If you check the size tab in the inspector, the view height is actually set to 460 (allowing for the 20 pixel status bar).
You can choose to include a top bar or a bottom bar and it will "simulate" those by adjusting the content height for you. This is just a positioning simulation so you can lay out your controls. At runtime, it's assumed you'll load the view into the proper viewcontroller which will have the proper chrome so it should all look right.
A lot of IB numbers are there for relative positioning. When you add the view to a navcontroller or a tabview, this view becomes a child of those parent views and by default they autoresize subviews. So if you've "simulated" for that top bar in IB, your controls should all be lined up properly and flow into the right place and you should see what you expect (of course, depending on what parent control ends up with your subview as a child).
BTW, you're missing out a lot of convenience by not using IB to wire up the controls and connecting them to IBOutlets. It really helps take out a lot of manual effort and extra code. It's like Superman refusing to use his X-ray vision and instead deciding to punch through walls :-)
Answer: IB doesn't always show correct origin/location coordinates, and some things, like UITabBarController, resize the view to be what they want it to be no matter what you set it.
Ive created a multiview application that uses multiple controllers to display and control views. The problem Im having is, when the simulator initially loads the view the header is partially covered by the bar at top of screen and the tool bar at the base is not touching the base of the screen. I used the Interface builder size attributes to control the view when the iphone rotates and it works perfectly. All smaps into place perfectly both in landscape and portrait mode AFTER a rotation but the problem is with the initial load before a rotation occurs.
Your thoughts a much appreciated.
Tony
I grappled with this issue for days and days--no amount of fiddling in IB worked.
Ultimately I got it to work by adding this line:
mainViewController.view.frame = window.screen.applicationFrame;
to the application:didFinishLaunchingWithOptions: method. (Where mainViewController is the primary UIViewController).
I've had issues with views being clipped by status, nav, and tab bars. I've fixed most of them by using the Simulated Metrics feature in Interface Builder. That way what your laying out in IB is a lot more accurate to what your actually going to get.
I ran into this issue too. Specifically, when displaying an ADBannerView, my whole view would shift and be under the status bar and leave a little empty space just the size of the status bar at the bottom of the iPhone screen. Here's how I solved it : (Adam's answer here helped me figure this out):
// In the function that displays an iAD Banner
CGRect contentFrame = self.view.bounds;
CGRect myStatusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
CGFloat statusHeight = myStatusBarFrame.size.height;
// Set the view's origin to be under the status bar.
contentFrame.origin.y = statusHeight;
I needed to set the origin of my view to be below the Status bar, and that solved the issue for me.
The problem is that you're adding your controller "incorrectly" according to Apple docs (although IMHO Apple designed it badly - the default should be that you don't need to shift!)
if you're going to have a status bar, Apple requires that you "manually" shift all your controllers down by 20 pixels (more accurately, by the height of the statusbar - although that's always 20 pixels today, Apple lets you request the height at runtime, from the "statusBarFrame" property in UIApplication)
Apple's classes - e.g. UINavigationController / UITabBarController - automatically shift themselves down by 20 pixels when they're added to the screen. Both classes have a bug where they will do this shift even if they are not the main controller - so your app suddenly shifts down an extra 20 pixels, leaving 20 pixels of white space at top.
But, when they rotate, those classes often "get it right" and move back into place. Or vice versa.
c.f. this link for a much more detailed explanation of what's going on, and how to write your code the way Apple wants you to:
http://blog.red-glasses.com/index.php/tutorials/iphone-auto-rotation-for-intermediate-developers-tutorial-1/