When in the view reload resources when orientation changes? - iphone

I have view that have many subviews, and each have it's own graphics, different for portrait and landscape orientations. When should I load the new graphics when the orientation changes?
If shouldn't be layoutSubviews, I don't also like the idea of reloading resources in view from UIViewController, because of complicated view hierarchy that I have (it would require to pass this information down).
There is also option to register in NSNotificationCenter for orientation changes in each view, and load new resources when it changes. But I don't quite like it either, because I believe that there should be mechanism in iOS that enables that. Or, maybe I should think in a different way, and build different views for portrait and landscape...
What do you suggest?

I would have your subviews all extend a custom view class that has a -setOrientation: method that swaps between the portrait and landscape graphics. Then in your view controller I would override -willRotateToInterfaceOrientation:duration: and add a loop that sets the orientation for all of the children, thereby causing the graphics to swap when the orientation changes.
I think that's the most straighforward way to do it. Using NSNotificationCenter could be tricky and you're left without a guarantee that every child will get the notification.
Anyway, that's how I'd do it. Let me know if you need examples.

Related

Auto-Layout [Snapkit] change constraints on rotate

I have built an app that uses no interface builder using Snapkit to create my Auto-Layout constraints. Everything looks fine in portrait, however a few screen's need some landscape specific constraints.
I've searched here and Google in general for a quick intro on doing this, but couldn't really find anything that was applicable (everything I found was based on using IB or used size classes instead of orientation - I specifically want landscape, not compact vs regular).
So, all my auto-layout constraints are set up in viewDidLoad at the moment. No doubt at very least, the ones that will be orientation dependant need moving to some kind of delegate/callback method on UIViewController, but I don't know know what that is...
How do I detect an orientation change in order to change my constraints?
How do I get the current orientation (so when I first load the view controller I can set the right constraints... Or is the function from my above question always called at least once for each VC on load?)
Outside of a ViewController, such as custom UIView's, how do I detect the orientation change? Should i send out a custom notification event? I'd rather not have my UIViewController tell every subview it has that orientation has changed.
Thanks for any help :)
I would personally use this function:
override func viewWillTransitionToSize(size: CGSize,
withTransitionCoordinator coordinator:
UIViewControllerTransitionCoordinator) {}
And then when those changes are detected call setNeedsLayout and layoutIfNeeded which should trigger a redraw of all of your subviews which can then handle setting constraints for specific orientations

Where is the right place to customise your view?

I was thinking of either viewDidLoad or inside my view subclass in awakeFromNib (since I load the view from nib). From the design point of view, encapsulating the customisation inside the view subclass sounds better. What are other options?
For me:
If the UI changes require coordination with the app's model, I generally do it in the view controller as I like to think of that as the gatekeeper between the model and the view. If it's creation of controls, I may do it in viewDidLoad, sometimes viewDidAppear. If it's re-layout of stuff based upon orientation changes, I'll do it in viewWillLayoutSubviews.
For anything of complexity that does not require extensive interaction with the model, I'll do in the view subclass.
The obvious other alternative it to design it in Interface Builder (with the appropriate autosizing masks and/or autolayout constraints) so you don't need to do anything programmatically. Often people are doing layout changes based upon orientation or size of the control that could have been taken care of automatically through judicious autosizing settings or autolayout constraints. Clearly this is often not possible, but don't overlook these if you're just adjusting layout based upon the size of the main view.

How do i make orientation work in my app?

The way my app currently deals with orientation is it repositions all of the items in the view, the layout of which can change as the user interacts with it. I've had numerous problems, such as view's not appearing, views changing before the screen rotates etc. I'm wondering the best way to deal with orientation?
If the landscape-layout is completely different from the portrait-layout I just load all subviews in the init-method of my UIView-subclass and added them as subviews.
The whole magic is done in the layoutSubviews-method where I only check in which orientation I am at that moment. Never call alloc, addSubview, removeFromSuperview, ... methods in layoutSubviews. The layoutSubviews should only contain code that sets the frame-properties of subviews.
Referring to your problems:
view not appearing: maybe forgot an addSubview-call
views changing before the screen rotates: you probably update some frame-properties of subviews outside the layoutSubviews-method
One possibility - if your app only works with one orientation, disallow orientation changes. This is a reasonable response, some apps are only usable in one view.

iPhone orientation management : what is the most efficient way to do?

I need to develop an iPad application which should manage the two orientation mode (landscape and portrait).
According the official Apple iOS documentation, there are 2 ways to proceed.
-The first one consists in adjusting views element when the rotation event is received. The main advantage is that we had only one ViewController
-The second one consists in displaying a specific ViewController for each orientation. Therefore, we have 2 ViewControllers.
The second approach seems to be nice, but I'am afraid by the numbers of ViewController that will be needed. What's more, the "data synchronisation logic" in the ViewControllers will have to be duplicated (or isolated from the ViewController) to be used in both orientation.
The application I need to develop will contain many "full custom elements" and many ViewControllers.
If anyone has advices or experience feedback, it would be really appreciated ;)
Thank's for reading !
The second way should rather be: using 2 different views (one for portrait, one for landscape) and swapping the view controller's view in willRotateToInterfaceOrientation:. No need to duplicate your data logic.
Which way to use? I would say: it depends.
If the lanscape and the portrait modes differ only by the position / size of views, I use the first one (plus you'll get nice animations of the frame changes)
If landscape and portrait are too different, I prefer the second one.
I usually solve this by taking advantage of the autoresizing techniques in the view combined with the implementation of willAutorotateToInterfaceOrientation and willAnimateRotationToInterfaceOrientation methods in the view controller.
With autoresizing techniques you can easily resize standard UI elements provided by Apple. If your UI elements doesn't have an impossible layout, you can apply the autoresizing techniques to them too. You must set the autoresizesSubviews property to YES in the parent view controller and select an autoresizing behaviour for each subview. For example, if you want it to resize to the right maintaining the view centered, you can apply the autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin mask in the subview.
If the autoresizing techniques doesn't do the trick, then you will need to resize each conflicting view separately by implementing the - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration in your view controller. If you have "full custom elements", you will need to resize them this way.
In my particular experience, I prefer to have only one view controller and one view for all orientations and manage them with these two techniques.
Hope this helps you!

Making view transitions fast - do you use this hack?

I have an iPhone app that displays a modal view controller. The modal view controller shows two instances of a custom subclass of UITextView called RoundedTextView, an MKMapView, and a UIToolbar. I construct the viewController only once, and reset its data and present it each time the user summons it.
When showing this view controller with presentModalViewController, I noticed that the animation to show the view was choppy on the 3G. So, to speed it up, I set the alpha of the MKMapView and the two RoundedTextView objects to 0 on viewWillDisappear and back to 1 on viewDidAppear. This made it nice and fast. I also presume that I could remove the views from the superview to speed it up as well.
Does anyone else jump through these kind of hoops on the iPhone. Is there something else I should be doing to avoid this hack?
It's not a hack to simplify drawing during animation in order to make the animation more smooth. It is indeed a very valid technique.
You may be able to achieve similar performance improvements by setting all UI elements to Opaque, a technique also used to fix table view cell performance issues. You just have to make sure background colors match.
The main problem I had was I subclassed UIButton to make gradient buttons and I had the boundary mask enabled. This made the performance terrible. I removed that option and made my buttons square and it's blazin now.