Question

The idea is to handle two different views, depending on device orientation.

Basically, if we exclude the views, the controller itself is only one piece of code. It is capable of handling any of the two views — either because IBOutlets bear the same name in the two IB storyboard viewcontrollers or because it uses an if statement against the device orientation.

I tried two different ways to do that, but I still face with one issue: I ended up with two actual controller instances, each of them running the same code (hence twice the threads and others pieces of code are run simultaneously).

I want to get rid of one and only have one instance running.

What would you suggest? There is probably a better way to handle my use case, isn't?

My code is as follows:

- (void)loadControllers
{
    self.firstController  = (DashboardViewController*)[[self storyboard] instantiateViewControllerWithIdentifier:@"DashboardPortrait" ];
    self.firstController.isDashboard = NO;

    self.secondController = (DashboardViewController*)[[self storyboard] instantiateViewControllerWithIdentifier:@"DashboardLandscape"];
    self.secondController.isDashboard = YES;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [self loadControllers];

    DashboardViewController *viewController = self.firstController;
    [self addChildViewController:viewController];

    viewController.view.frame = self.contentView.bounds;

    [self.contentView addSubview:viewController.view];

    self.currentViewController = viewController;
}

- (void)setOrientationPortrait:(BOOL)portrait {
    DashboardViewController *viewController = portrait?self.firstController:self.secondController;


    // Make sure the two view controllers share the same parent.
    [self addChildViewController:viewController];

    // If not same parent, dont transition
    if (viewController.parentViewController!=self.currentViewController.parentViewController) return;

    [self transitionFromViewController:self.currentViewController
                      toViewController:viewController
                              duration:0.0
                               options:UIViewAnimationOptionTransitionNone
                            animations:^{
                                [self.currentViewController.view removeFromSuperview];
                                viewController.view.frame = self.contentView.bounds;
                                [self.contentView addSubview:viewController.view];
                            }
                            completion:^(BOOL finished) {
                                [viewController didMoveToParentViewController:self];
                                [self.currentViewController removeFromParentViewController];
                                self.currentViewController = viewController;


                                // Direct video to the destination, current controller
                                AppDelegate *app = (AppDelegate*)[[UIApplication sharedApplication] delegate];

                                [app faceRecognitionAttachPreview:self.currentViewController.previewView];
                            }
     ];

    self.navigationItem.title = viewController.title;
}
Was it helpful?

Solution 2

So far, so good.

In my context, I believe the simpler is the best solution. I then dropped my two-vc architecture coupled with a vc with an embed view in favor to one vc with one view.

The point is that you need to write code to handle the UI differences In my case, I also had to changed the way the hierarchy of the views in the vc in order to be able to disable some of them at runtime. Also, I had to enlarge a view for the horizontal mode, and I use the scale transformation of the layer. The bad point is that it actually zoom in at graphics level. The texts are not as slick as if you increase the font size. This is something I will do very soon to preserve the best quality possible.

The code I wrote so far in the device rotation selector as follows:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {

    static CGRect actionViewRect = (CGRect){0,0,0,0};

    if (!actionViewRect.size.height) actionViewRect = self.actionView.frame;

    //self.containerView.hidden = YES;

    [UIView transitionWithView:self.view
                      duration:0.3f
                       options:UIViewAnimationOptionTransitionCrossDissolve
                    animations:^{

                        // From portrait to landscape
                        if (UIInterfaceOrientationIsPortrait(fromInterfaceOrientation)) {
                            self.navigationController.navigationBar.hidden = YES;
                            self.tabBarController.tabBar.hidden = YES;

                            self.statusBar.hidden = NO;
                            self.actionView.hidden = YES;
                            self.containerViewTopToSuperView.constant       = self.navigationController.navigationBar.frame.origin.y;
                            self.containerViewBottomToSuperView.constant    = 0;
                            CGRect rect = actionViewRect;
                            rect.origin.y    = actionViewRect.origin.y+actionViewRect.size.height;
                            rect.size.height = 0;
                            self.actionView.frame = rect;

                            // -- location view (bigger)
                            CGFloat
                            s = 1.5;
                            self.locationView.layer.transform = CATransform3DMakeScale(s, s, 1);

                            // -- HUD view (bigger)
                            s = 1.5;
                            self.hudLeft.layer.transform = CATransform3DMakeScale(s, s, 1);

                        }
                        // From landscape to portrait
                        else {
                            self.navigationController.navigationBar.hidden = NO;
                            self.tabBarController.tabBar.hidden = NO;

                            self.locationView.layer.transform = CATransform3DIdentity;


                            self.actionView.hidden = NO;
                            self.actionView.frame = actionViewRect;
                            self.containerViewTopToSuperView.constant       = self.navigationController.navigationBar.frame.origin.y
                                                                            + self.navigationController.navigationBar.frame.size.height;
                            self.containerViewBottomToSuperView.constant    = self.tabBarController.tabBar.frame.size.height;

                            // -- location view (standard)
                            self.hudLeft.layer.transform = CATransform3DIdentity;                        }

                            // -- HUD view (bigger)
                            self.hudLeft.frame           = (CGRect){.origin=(CGPoint){0,0}, .size=self.hudLeft.frame.size};
                    }
                    completion:^(BOOL finished) {
                        // Direct video to the destination, current controller
                        AppDelegate *app = (AppDelegate*)[[UIApplication sharedApplication] delegate];
                        app.previewLayer.orientation = [[UIDevice currentDevice] orientation];

                        //self.containerView.hidden = NO;

                        //[UIView setAnimationsEnabled:YES];

                    }
     ];
}

OTHER TIPS

According to Apple, it is best practice to have two separate view controllers for the two orientations if there are significant differences between the two. They say:

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. Using two view controllers is simpler and more efficient than making major changes to your view hierarchy each time the orientation changes. It allows each view controller to focus on the presentation of data in one orientation and to manage things accordingly. It also eliminates the need to litter your view controller code with conditional checks for the current orientation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top