Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ContentInset set wrong when dismissing view controller in iOS

In my iOS application (developed using Xamarin) I am using a custom container view controller to switch between different child view controllers (which all contain a UITableView) associated with the segments of a UISegmentedControl.

At the beginning I was having an issue with the wrong contentInset assigned when switching to a new view controller, as the view was positioned underneath the navigation bar. I solved the issue with the solution presented in this other stackoverflow question, and it worked like charm.

The problem now is that one of the child view controllers presents another view controller modally, and when it is dismissed, the contentInset is set wrong again. In this case with the tableview starting at the middle of the available space, with quite some white space between the navigation bar and the first row.

I was trying to understand which method implicitly changes the content inset, but I no luck. So, what method could be the culprit of this behaviour?

I have tried with setting automaticallyAdjustsScrollViewInsets both to true and false, but the result is the same.

UPDATE: It seems that the issue is presented only in iOS 8, but not in iOS 7

like image 433
papafe Avatar asked Jul 28 '15 08:07

papafe


1 Answers

Synposis

Get rid of contentInset. Insert a UINavigationController between the Segmented Control View Controller and each table view controller.

How it looks in the Storyboard

While you are not required to use a Storyboard to implement this solution, it makes for a very graphic user interface.

enter image description here

Hook up the Segmented Control

Again, I use Storyboard for simplicity and clarity. You are welcome to create each navigation controller and view controller programmatically if it suits you.

This is the entire class. 30 lines of code total.

class SegmentedControlViewController: UIViewController {
    var segmentViewController:UIViewController? = nil

    override func viewDidLoad() {
        super.viewDidLoad()
        let vc = self.storyboard!.instantiateViewControllerWithIdentifier("nav0") as? UIViewController
        self.addChildViewController(vc!)
        self.view.addSubview(vc!.view)
        self.segmentViewController = vc
    }

    @IBAction func segmentedControlValueChanged(sender: AnyObject) {
        if let segmentedControl = sender as? UISegmentedControl {
            let identifier = "nav\(segmentedControl.selectedSegmentIndex)"
            let vc = self.storyboard!.instantiateViewControllerWithIdentifier(identifier) as? UIViewController

            self.addChildViewController(vc!)
            self.transitionFromViewController(self.segmentViewController!, toViewController: vc!, duration: 0, options: .TransitionNone, animations: { () -> Void in
                self.segmentViewController!.view.removeFromSuperview()
                //vc!.view.frame = self.view.bounds
                self.view.addSubview(vc!.view)
            }, completion: { (Bool) -> Void in
                vc!.didMoveToParentViewController(self)
                self.segmentViewController!.removeFromParentViewController()
                self.segmentViewController = vc
            })
        }
    }
}

Compatibility

The above code does not show how to push a view controller using Segue Present Modally or `Show (e.g. Push) since it is out of the scope of this response and both have been verified.

Built and tested on iPhone 4s to 6 Plus, every iPad, Portrait, Landscape, orientation changes, iOS 7 & 8.

like image 101
SwiftArchitect Avatar answered Sep 18 '22 14:09

SwiftArchitect