I've been looking for a great pattern to deal with the orientations on the iPad without any luck. I know that there are already a lot of topics about this on stackoverflow but no one is really great so don't waste your time adding this topic as a duplicate.
As any iPad application, you have to deal with (at least) 2 orientations (landscape and portrait).
How are you dealing with this ?
Do you use two different ViewController ?
Do you use the willRotateToInterfaceOrientation:duration methods ?
How do you avoid duplicate code ?
Thanks
You won't find a single pattern because the best method varies depending on the needs of each particular app.
If the views are simple, then rotating the view's elements takes little code. If the views are complex and/or the elements change between orientations, then I would recommend using two view controllers.
You can avoid duplicate code in multiple controllers by creating a super class for the controllers that contains all the shared functionality. If you use nibs, you will often find you need only change the nib file for each subclass.
Related
I am making modifications to an existing iPad application, and I'm having a hard time dealing with really messy scenes in storyboards. Almost every scene in the app consists of multiple views laid one on top of the other, each containing a different set of controls. Depending on the situation or data coming into the scene, some views are hidden, and others are shown.
It takes a LOT of time to decipher such scenes, and even when I figure out what changes I need to make it's terribly difficult to make those changes, and easy to screw up other things.
As an example, the following scene has 3 views that could appear (Start View, End View, Drawer History), depending on the situation, and they are all laid out on top of each other...
This seems like a terrible way to handle this, and I'm having a hard time believing this is standard practice, but I'm not finding much in the way of alternatives. I find very little in the way of questions where people are dealing with this problem, and the tutorials on how to design user interfaces seem to be too simplistic and never deal with scenes that are complex enough to run into this problem.
Unfortunately, this app is my primary introduction to doing user interfaces in iOS, so it has apparently become the default solution in my head. I've tried many tutorials, but they take a long time and don't seem to ever get to a situation that needs such a technique to solve it.
I would hope there would be a solution where each alternate view in the scene could be laid out on its own, and be made to appear within a placeholder view as needed.
What would be a more enlightened / more manageable approach?
That's what you'll get with Storyboards/Nibs/Xibs. I'm not saying coding your UI is better than using interface builder, but it is, at least for me. I believe, as far as I know, there's no other way to handle such multiple layers of views in one view controller in interface builder. I actually used to use interface builder before and that's how I add multiple layers of controls too. Sometimes some views are initially made hidden, but that would probably confused me or the other developer looking at the layout. Sometimes I extend the viewcontroller height to know that there's a view container with a constraint a thousand constant or a negative thousand constant to make it hidden and ready to animate when it's needed to be shown.
There are ways to somehow improve and organize your Storyboards. You can separate modules into different storyboard files; you can use references; avoid segues; and whatnot. It's still an individual or team's preferences.
Some ref:
https://cocoacasts.com/organizing-storyboards-with-storyboard-references
https://medium.com/#stasost/xcode-a-better-way-to-deal-with-storyboards-8b6a8b504c06
EDIT:
I'm thinking you could also layout separate view containers into a separate xibs, and then call them or layout them when needed. But that would add more files to your project.
In my app, most of the views have major UI design differences when used on a small device (e.g. iPhone portrait) vs a large one (e.g. iPad fullscreen.) The basic architecture remains the same, but each View Controller needs to display a very different set of UI elements.
I could respond to size changes in Interface Builder, by Installing and Uninstalling elements and Auto Layout Constraints according to size class, but this would be extremely unwieldy and fragile.
In ye olden days (~2014), Apple's advice was:
If you want to present the same data differently based on whether a device is in a portrait or landscape orientation, the way to do so is using two separate view controllers. One view controller should manage the display of the data in the primary orientation (typically portrait), while the other manages the display of the data in the alternate orientation.
Despite the advent of Size Classes, this strikes me as still the best solution for my particular design (remembering to take size classes and split-view, slide-in to account.)
Question 1: at what point in my app should I detect the trait changes?
Question 2: (presuming that I have loaded an alternate view controller from a storyboard) in response to the trait change, how should I best transition/present the alternate view controller?
I am asking the same question asked here: Adaptive swapping of View Controllers in response to Size Class Trait changes iOS 9
Because nobody answered the original question.
If you're talking about trait changes during runtime, for example device rotation and iPad multitasking, you can use viewWillTransitionToSize (see this question for sample code) and adjust the view hierarchy (with animations, if you like) within this method. Just use the normal view and view controller presentation methods to add / remove presented controllers, or child controllers and their views.
If you're talking about trait changes at launch time (iPad vs. iPhone), just create a different storyboard or root view controller for those two devices and set it in your app delegate. This approach will have the downside of not offering an iPad-like experience for the plus-sized iPhones in landscape without additional work on your part, though.
I want to challenge something you said, though:
I could respond to size changes in Interface Builder, by Installing and Uninstalling elements and Auto Layout Constraints according to size class, but this would be extremely unwieldy and fragile.
Xcode 6 and later support "unified storyboards" which the docs describe like so:
A storyboard can add or remove views and layout constraints based on the size class that the view controller is displayed in. Rather than maintaining two separate (but similar) storyboards, you can make a single storyboard for multiple size classes. First, design your storyboard with a common interface and then customize it for different size classes, adapting the interface to the strengths of each form factor.
Xcode 8 makes it especially easy to design these highly adaptive views. You can switch into an editing mode for a particular size trait, and even preview how a view controller will look on a variety of devices. Before continuing further down your current path, I encourage you to dig in to the improvements in Xcode 8 if you haven't already and see if you can make unified storyboards work for your use case.
I know this is a question that has been asked quite a bit, but it's iOS 9 and I still don't have a clear idea about what to do. For starters, here is what I seem to be surmising from all the data available:
Storyboards let you create segues. [I've never been a big fan of this answer because segues are often the least harrowing part of creating the UI layout for me.]
Xibs can let you create multiple top-level views. (Storyboards vs. the old XIB way) [I don't think I've ever used this much, though it seems rather helpful.]
Storyboards - Creating UITableViewCells is easier. [In my opinion, it's cleaner to create xibs for the cells and just invoke them in cellForRowAtIndexPath].
Storyboards can turn into one giant ultramassive file that is hard to edit. [I've seen this happen in practice and it is a big drawback, but at the same time...]
Storyboards let you arrange all your Views in one place with the layout shown as well. [This seems to be a big help for me. But then, over the years I've found doing this in code much easier. Which brings me to my final question.]
What is the performance aspect of both of these two things. My app is essentially the following :
A top level hierarchy of interconnected view controllers, not more than 5.
A large number of disparate, independent view controllers that range from Scroll Views to TableViews to static Imageviews.
Autolayout, size classes, the works.
For each of these view controllers, what is the performance of creating a storyboard for each of them vs. creating a xib for each of them. More importantly, what would be a good way to lay out an app like the one I've mentioned.
You definitely want to use storyboards for laying out view controllers - simply because you get access to topLayoutGuide and bottomLayoutGuide which the XIB editor won't give you.
For other views, it's a matter of preference. I tend to use XIBs for table view cells simply because I tend to reuse them on different screens and prefer to have them in their own files.
I would actually advise against manually writing view code where possible simply because it's much harder to read and work out how views are laid out, especially for developers who didn't write the code originally! For simple, dynamically sized things this can be fine, but if you're trying to lay out view controllers with different constraints depending on the size class it's going to end up a bit of a mess.
Yes, it's a pain to deal with merge conflicts of these files, but with iOS 9 you can split up view controllers into different storyboards a lot more easily using view controller references. Personally I find the inconvenience of merging storyboards/XIBs the lesser evil of having to write everything in code.
It sounds like a Storyboard is the right thing for your current project. However, my experience has been that Xibs and Storyboards are problematic in the real world, for these reasons:
extremely idiosyncratic from developer to developer, so it is tricky to build good storyboards as a team
black boxes, so they require a tremendous amount of knowledge to master (unbelievable amount of hidden behavior). Only the most superficial semantics are covered in the documentation.
internationalization is made much harder by being split up, especially if you have internationalized messages not contained in the Storyboard/Xib.
backwards compatibility breaks annually / deprecation guaranteed over time. This is especially difficult if you try to maintain compatibility with older devices.
As soon as more than two devs started touching our code we rewrote everything to avoid Storyboards and Xibs altogether, and we became much more productive.
If you have to deal with any of those real world situations, I heartily recommend programmatically creating all of your views. There is even an app that makes this easier (and is way more scalable). I have no relationship with this company or product, but it is hands down a better solution.
http://www.paintcodeapp.com/
I'm trying to develop a universal iOS app and ideally I'm trying to get as much code re-use as possible.
I'm using storyboards so the UI is segmented into scenes.
In the iPhone storyboard the particular scene in question is best suited to a table view.
In the iPad storyboard, the equivalent scene in the storyboard would ideally implement a UICollectionView and so render the content in a grid.
Both views should implement a pull-to-refresh control which in one case is going to call a [UITableView reloadData] and in the other a [UICollectionView reloadData].
Anybody any advice on how to get the maximum amount of code re-use, ie. what does the controller class look like?
1 option would be to have 1 monolithic class that conforms to both the UITableView protocols and the UICollectionView protocols but this doesn't feel right.
Another option would be to have a base class and then subclass it with specialisations for iPhone and iPad. Whilst this feels cleaner, I'm still thinking there might be a better way. In my first attempt at this it felt like there was more code in the specialisation classes than there was in the base class.
The third plan I've considered is simply to use a UICollectionView in both apps therefore eliminating the complexity of the controller. Hopefully I could force the layout of the collection view to be a grid on the iPad whilst tell it to mimic a table view on the iPhone.
Whilst on the face of it this sounds easy I'm struggling to make a UICollectionView work exactly like a table view would do normally.
Any advice guys?
Many thanks,
CA.
If you are not using some of the specific UITableView features[1], making UICollectionView look exactly like a table is trivial. I think I would go for using UICollectionView as it will allow more flexibility in the future and you will have to use it anyways.
When you are talking about code reuse you probably mean the DRY principle. It just says you should not write the same code or the same information twice, but I don't think this is your main issue here.
I would use a UITableViewController on the iPhone and a UICollectionViewController on the iPad. I think this is the cleanest and easiest way to go. What exactly do you hope to reuse among both controllers? The both require two different delegate protocols, so most of the methods will be specific to one platform. You will need two NSFetchedResultsController if you're using Core Data, but reusing the fetched results controller code only makes sense if you need the same data on both platforms.
If you create a new universal project in Xcode you will get a basic project setup that looks different on iPhone and iPad. Try to understand it (there are some details to pay attention to) before you start programming, I think it will answer at least some of your questions.
I am looking for some clarification with regards to view controllers and views. Should one view controller be used exclusively to control one view?
Basically, my portrait view is going to be a 4x3 grid of buttons (within a scrollview). When i rotate the view to landscape, i am going to want maybe a 6x4 grid.
Obviously the functionality for handling the buttons' clicks etc will be the same in either orientation, so it would seem a lot of effort to duplicate this for landscape.
How should i get the view controller to use the correct view xib?
Should i have two seperate xibs? I have tried every combination of autoresize masks and not having much luck.
I'm not sure of the correct way to go.
Thanks.
i do not think that the above one answered the question of joec. joec want to know, if it is bad or good to have 2 nibs (i.e. landscape.nib and portrait.nib) and manage the views in that 2 nibs with 1 uiviewcontroller.
my understanding of the mvc design pattern is, that a ViewController really SHOULD manage different views. but when i look at the internet, in cause of cocoa touch, often people says that it is BAD (whatever this means) when a UIViewController switches his view-property at runtime. thats confusing to me. why should a viewcontroller not be able to switch views ? why should i build some strange "master"-viewcontroller, which manages 2 other viewcontrollers, and everyone of this manages his own view. in case of landscape and portrait abstraction (or i.e. iphone-gui and ipad-gui abstraction) the code in the gui-business-layer (the event-code etc. in the viewcontroller) is exactly the same for different views. the style of the views is not. so that should one of the benefits of a mvc-implementation.
sorry, but that seems not logical for me, apple.
any thoughts ?
edit says:
it seems that apple provides some strange sort of workaround to solve this problem (hate me, but for me it is nothing more than that, because i see no really straight-forward design implementation for managing and handling views in the UIViewController class):
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/BasicViewControllers/BasicViewControllers.html%23//apple_ref/doc/uid/TP40007457-CH101-SW26
i found this link in the following stack overflow thread:
Want to use muliple nibs for different iphone interface orientations
thanks to Michal for that one.
You can also try to change your views and subviews sizes etc.
Take a look here Madhup expained It before. Changing UIView on orientation change