I am trying to setup my UI on my universal app. I have a storyboard setup with size classes, a fairly simple UI. I have my view controller with a view in. Inside this view, I draw a chart so this can only be updated using setFrame.
This is where my problem begins. I set my graph to be the screen width. However, when the view initially runs, the size class seems to be unknown.
As the default 'Any' size in my storyboard is 600x600. My view thinks it should draw 600 wide on my iPhone, which clearly isn't this wide.
It is only after I physically move the iPhone to toggle an orientation change, that it updates and recognises the correct size.
So my question is, how do I prevent this problem? I need my UI to know what size to be from the get go, not just after the user rotates their iPhone.
However, when the view initially runs, the size class seems to be unknown.
It is unknown to the view and the view controller, because at that time the view controller is not yet part of the interface and has no environment. But it is not unknown to UIScreen.mainScreen(). So if you need this information very early, that is who to ask.
However, as you've been advised in a comment, it also sounds like you may simply be doing this too early. Nothing in a view controller's view, including the view itself, has achieved its actual size until viewDidLoad or later.
There are two to prevent this problem
(1) Load your entire method in
-(void)viewDidAppear:(BOOL)animated
{
}
(2) Do the following step
Go to file Inspector
Uncheck "Use size classed
Related
As known different views can be added for each screen unit class(Regular, Compact) By picking the desired unit classing then clicking the Vary for Traits button.
Then, connect the views to your controller twice using outlets. one for general and one for that unit class.
In viewDidLoad I printed the values of both views and noticed that both
of them are not nil.
Shouldn't I have one of the views equal to nil since this is not its unit class? How does view traits realy work?
All views (and constraints) are instantiated and referenced with their corresponding outlets when your storyboard scene (or nib) is loaded — no matter what size class they are installed on.
From Apple's Auto Layout Guide:
When the system loads a scene, it instantiates all the views, controls, and constraints, and assigns these items to the appropriate outlet in the view controller (if any). You can access any of these items through their outlets, regardless of the scene’s current size class. However, the system adds these items to the view hierarchy only if they are installed for the current size class.
This is because your view's size class does not only vary depending on the device, it may also change when you rotate your device or do multitasking on an iPad. When you change your layout as a response to a user action (like a tap) you really wanna make sure that you update the layouts for all your size classes.
Example:
Say you have a simple "register view" with a username text field where users can claim their unique username. You want to give the user immediate visual feedback if the username he typed in is already taken or not.
You decide that on a compact size class (iPhone in portrait mode) there is just enough space to show a litte red cross (❌) on the right edge of the text field. On the iPhone 6/7 Plus in landscape mode however, there is enough space to show the user a little more information and so you choose to show a label "Username taken, please try another one!" next to the red cross on the regular size class.
Now every time the user has entered a new character in the text field you can validate the input and then update the UI like this:
func updateUI(isUsernameAvailable: Bool) {
redCross.hidden = isUsernameAvailable
usernameTakenLabel.hidden = isUsernameAvailable
}
At this point you can be sure that the UI is up-to-date no matter how often the user rotates the devices. If the usernameTakenLabel was not instantiated here you would have to somehow remember that the label should be hidden/visible once it shows up with an extra instance variable and then use that variable to actually hide/reveal the label once it is instantiated i.e. when the size class width changes which bloats your view controller and is pretty error prone.
Forgive me if this is a duplicate. I thought for sure this would be an obvious question.
I have a container in a storyboard, which is of class ModelViewController (the whole view controller). From ModelViewController I need to get the width and height of the container. I am currently trying:
self.view.bounds.size
Which yields 0.563380 and 0.000000. I also tried
self.view.frame.size
Which yields the dimensions of the entire screen. What am I missing here?
From this post
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.
And the comment
Actually, you should move geometry changes to -viewDidAppear pre-iOS 5 and to -viewWillLayoutSubviews for iOS 5+. -viewWillAppear: may not actually have the correct bounds/orientation if the view is being animated.
I found the solution. The correct dimensions are indeed given when called from viewWillLayoutSubviews. I was calling from viewDidLoad giving incorrect results.
I know this has been asked before, but none of these solutions work, and that's the reason of my posting. Please do not close before considering my case.
My plist already has UIViewControllerBasedStatusBarAppearance = false.
I have already tried applying deltas, but to no result.
Changing the top level view frame in ViewWillAppear (like self.view.frame) did not succeed.
I thought of increasing the view height (storyboard attribute inspector), in combination with deltas, but my top level view X, Y are disabled in storyboard attribute inspector.
My main view doesn't have any children views because I load them into main view either dynamically or load them from XIBs which are again shared by more than view controllers. These XIBs provide layout for both Portrait and Landscape. I don't know what approach is ideal for this kind of configuration, but I would like it better if solution lies along these lines.
This approach worked partially, but gave me inconsistent results.
What makes the solution tricky is the fact that I have to support all 4 orientations - this is something I handle in code via didRotate and willRotate delegates for my other views, but failing to do it for statusbar.
Please help...
Could this link be of any help?
You might have to use the new setEdgesForExtendedLayout: method to get this working consistently?
Also, have a look at these official docs if you haven't already done so.
I ended up writing my own function to shift my all subviews (remember, not top level views whose frame is fixated by IB).
It didn't spoil my work but imagine if this was the case for a very big project with so many screens, the limitations would have made it a nightmare.
I'm trying develop my app for iphone 4 and 5. However I encountered problem with container view. My view looks like this:
Now, I tried to google a little bit, and found, that I can set size of my views in project settings by uploading picture in different sizes (so that all my views will get resized automatically). This is true for all my views except my container view.
So my second attempt was to size my view in appdelegate like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
_window.frame = CGRectMake(0, 0, 320, [[UIScreen mainScreen]bounds].size.height);
}
This unfortunately did nothing to my container view.
Only solution I found so far, was to set height of my embedded table view, by setting it to 458 in size inspector in interface builder. This sets it to fit iphone 5 screen, however on iphone4 (and in simulator) it is too much and some of my rows are below screen (as I expected).
If anyone could help me, I'll be glad, because I really don't know how to deal with this problem ;)
Well I would look into your constrains and your origin settings, incase you made any changes without knowing. Here is an example:
Make sure the origin settings are set to the top left "dot" like in the image and check your constrains parents (Superview in this case). Tip: The key to editing constraints in interface builder is never to drag and drop anything once you've added it to the view. Move and arrange things by editing the constraints instead.
You can also turn off the Auto-layout and do it manually
Here is also a great article on auto-layout in interface builder and apples own documentation on Resizing the View Controller’s Views and children's views (which a container is).
My last tip before you either have to try my last solution (which is underneath) or get the answer from someone else, is to check your architecture settings.
If that does not help it might be caused by some unknown random error that is hard to find, and I would suggest that you try to clean your project first by clicking/holding down "Shift" "command" and "K", and if that does not work, just start a totally new project and copy all the code and files over to the new project. This should help since the problem that you have should not be accruing since it should be dealt with automatically, but seemingly random errors do accrue on occasions.
I hope one of the tips help you out, if not I'm sorry.
I have a custom UIView, which I have placed using Xcode (4). I need to set some default state, based on the actual bounds of the view. During awakeFromNib, bounds seems to be returning the size of the view in the storyboard layout in Xcode.
The view is in the detail side of a UISplitViewController, which in Xcode is the size of a full portrait iPad screen, but if the app loads in landscape mode then, via springs-and-struts, its size is changed, but this appears to happen after awakeFromNib.
Should I be setting this state in some other method?
It depends what sort of state you are setting - if it is dependent on the bounds then you'll need to reset it every time the device is rotated, presumably? In that case overriding setFrame: might be a better bet - be sure to call the superclass implementation before you do anything else, though.
The answer is was probably looking for, or at least the solution I have used, is to provide a public method in the UIView to be called by the parent UIViewController in viewWillAppear: