Mukesh
Mukesh

Reputation: 2902

UIStoryboardSegue animates property in subclass

I have a UIStoryboardSegue subclass for replacing current view controller with next view controller.

As we have a Animates property in interface editor, I want to access this property in the subclass.

enter image description here

My code is following:

class ReplaceSegue: UIStoryboardSegue {

    override func perform() {
        var viewControllers = source.navigationController?.viewControllers.dropLast() ?? []
        viewControllers.append(destination)
        source.navigationController?.setViewControllers(viewControllers.map {$0}, animated: true) // I dont want this `true` to be hardcoded
    }
}

Upvotes: 1

Views: 303

Answers (2)

malhal
malhal

Reputation: 30719

You shouldn't need a UIStoryboardSegue subclass for this. The docs state "You can subclass UIStoryboardSegue in situations where you want to provide a custom transition between view controllers". This means that a replacement without without any animation isn't a custom transition, thus shouldn't use a segue subclass.

The correct way to do replacement is to use a Show Detail (e.g. Replace) segue and inside the parent view controller that is managing the child view controllers implement the method showDetailViewController and replace the children, e.g.

@implementation DetailNavigationController

- (void)showDetailViewController:(UIViewController *)vc sender:(id)sender{
    [self setViewControllers:@[vc] animated:NO];
}

If you didn't know, the Show Detail segue (after magically instantiating the destination view controller) has a perform method that just calls showDetailViewController on self, and the base UIViewController implementation searches up the view controller hierarchy looking for one that overrides showDetailViewController, so you can intercept it and perform your custom code, before say it goes up to another parent that might implement it also like a split view.

Upvotes: 0

Sandeep Bhandari
Sandeep Bhandari

Reputation: 20379

As per comments in UIStoryBoardSegue class

The segue runtime will call +[UIView setAnimationsAreEnabled:] prior to invoking this method, based on the value of the Animates checkbox in the Properties Inspector for the segue.

So obviously you can read the value of animate check box by using

UIView.areAnimationsEnabled

So in my custom segue

class MySegue: UIStoryboardSegue {
    override func perform() {
        debugPrint(UIView.areAnimationsEnabled)
    }
}

This prints false if animate checkbox is unchecked or true if it is checked :)

So in your case

class ReplaceSegue: UIStoryboardSegue {
    override func perform() {
            var viewControllers = source.navigationController?.viewControllers.dropLast() ?? []
            viewControllers.append(destination)
            source.navigationController?.setViewControllers(viewControllers.map {$0}, animated: UIView.areAnimationsEnabled)
    }
}

I hope whats happening is already clear, incase you still have doubt, here is the explanation, iOS checks the animates checkbox value and uses it to set whether animations are enabled or not by calling setAnimationsAreEnabled with the value of animates check box in interface prior to calling perform() method.

So when the control reaches inside perform you can be assured that iOS has already read the value of animates check box and used it to set setAnimationsAreEnabled all you have to do now is to ask areAnimationsEnabled to get the value of animates check box.

So that should provide you the value of animates checkbox :)

Hope it helps :)

Upvotes: 1

Related Questions