Introduction
I'm creating a calendar app in which one of the screens has a landscape view and a portrait view. For simplicity picture the iOS apple calendar in which the landscape view is a week view (i.e. completely different than the portrait view).
Issue
I'm getting a sense of bad code structure and potential loss of efficiency in my current code. Since I basically use the users battery and CPU for the week view concurrently with the portrait view even though not everyone uses the week view. What is the better practice in implementing a different presentation depending on device rotation?
Question
- Which pattern would be the more efficient approach? Is there a third option I haven't considered that would result in better performance?
My attempts
(I've also included a code example (below) that shows my implementation of these attempts in code.)
Two
UIViewControllers that is segued and "popped" depending on conditions of device orientation inviewWillTransition(). Although that became quickly out of hand since the method triggers in all view controller currently in memory/navigationStack, resulting in additional copies of viewControllers in the navigation stack if you swap between right landscape and left landscape.Using one
UIViewControllerand twoUIViewsubclass that is initialized and communicating to the view controller through the delegate-protocol pattern. In which during theviewWillTransition()I simply animate an alpha change between the twoUIViewsdepending on the device orientation.
Code example
(I have provided two simplification to illustrate my attempts described above, methods such as dataSource and delegate methods for UICollectionViews are not included are not included in the example below.)
Attempt 1:
class PortraitCalendar: UIViewController {
let portraitCalendarView : MonthCalendar = {
// Setup of my portrait calendar, it is a UICollectionView subclass.
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(portraitCalendarView)
// Additional setup..
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if UIDevice.current.orientation.isLandscape {
performSegue(withIdentifier: "toLandscapeCalendar", sender: nil)
}
}
}
class LandscapeCalendar: UIViewController {
let landscapeView : LandscapeView = {
// Setup of the landscape view, a UICollectionView subclass.
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(landscapeView)
// Additional setup..
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if UIDevice.current.orientation.isPortrait {
navigationController?.popViewController(animated: true)
}
}
}
Attempt 2:
class PortraitCalendar: UIViewController, LandscapeCalendarDelegate {
let portraitCalendarView : MonthCalendar = {
// Setup of my portrait calendar, it is a UICollectionView subclass.
}
// UIView subclass with a UICollectionView within it as a week calendar.
let landscapeCalendar = LandscapeView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(portraitCalendarView)
view.addSubview(landscapeCalendar)
landscapeCalendar.alpha = 0
portraitCalendarView.alpha = 1
// Constraints and additional setup as well of course.
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if UIDevice.current.orientation.isLandscape {
navigationController?.isToolbarHidden = true
self.view.layoutIfNeeded()
landscapeCalendarDelegate?.splitCalendarViewWillAppear()
UIView.animate(withDuration: 0.1) {
self.portraitCalendarView.alpha = 0
self.landscapeCalendar.alpha = 1
}
} else {
self.portraitCalendarView.alpha = 1
self.landscapeCalendar.alpha = 0
}
}
}
Thanks for reading my question.