Snapchat-like swipe navigation between views in Xcode 6 and Swift)

前端 未结 7 641
清酒与你
清酒与你 2021-01-30 11:47

I\'ve been trying to implement swipe navigation between View Controllers in my app using the Swipe Gesture Recognizer and embeded Navigation Controller, but it doesn\'t look eve

7条回答
  •  终归单人心
    2021-01-30 12:29

    I'm not fond of the version given by lbrendanl because it does not use constraints. We can not custom it like we want. Here is the same version but with constraints :

    scrollView is an IBOutlet pined to the controller with 4 constraints with a constant to 0 at each sides to the controller's view.

    contentView is also an IBOutlet added as subview of scrollView pined to the scrollView with 4 constraints with a constant to 0 at each sides. It also has an equal height constraint and a width equal constraint. The width equal constraint is removed at runtime and only serves to calm down IB. This view represents the contentView of the scrollView.

    UPDATE iOS 9

     func setupDetailViewControllers() {
        var previousController: UIViewController?
        for controller in self.controllers {
            addChildViewController(controller)
            addControllerInContentView(controller, previousController: previousController)
            controller.didMoveToParentViewController(self)
            previousController = controller
        }
    }
    
    func addControllerInContentView(controller: UIViewController, previousController: UIViewController?) {
        contentView.addSubview(controller.view)
        controller.view.translatesAutoresizingMaskIntoConstraints = false
    
        // top
        controller.view.topAnchor.constraintEqualToAnchor(contentView.topAnchor).active = true
    
        // bottom
        controller.view.bottomAnchor.constraintEqualToAnchor(contentView.bottomAnchor).active = true
    
        // trailing
        trailingContentViewConstraint?.active = false
        trailingContentViewConstraint = controller.view.trailingAnchor.constraintEqualToAnchor(contentView.trailingAnchor)
        trailingContentViewConstraint?.active = true
    
        // leading
        let leadingAnchor = previousController?.view.trailingAnchor ?? contentView.leadingAnchor
        controller.view.leadingAnchor.constraintEqualToAnchor(leadingAnchor).active = true
    
        // width
        controller.view.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true
    }
    

    PREVIOUS ANSWER

        class ContainerViewController: UIViewController {
    
        @IBOutlet var scrollView: UIScrollView!
        @IBOutlet var contentView: UIView!
    
        // A strong reference to the width contraint of the contentView
        var contentViewConstraint: NSLayoutConstraint!
    
        // A computed version of this reference
        var computedContentViewConstraint: NSLayoutConstraint {
            return NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: .Width, multiplier: CGFloat(controllers.count + 1), constant: 0)
        }
    
        // The list of controllers currently present in the scrollView
        var controllers = [UIViewController]()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            initScrollView()
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
    
        }
    
        func initScrollView(){
            contentView.setTranslatesAutoresizingMaskIntoConstraints(false)
    
            contentViewConstraint = computedContentViewConstraint
            view.addConstraint(contentViewConstraint)
    
            // Adding all the controllers you want in the scrollView
            let controller1 = storyboard!.instantiateViewControllerWithIdentifier("AStoryboardID") as! AnUIControllerViewSubclass
            addToScrollViewNewController(controller)
            let controller2 = storyboard!.instantiateViewControllerWithIdentifier("AnotherStoryboardID") as! AnotherUIControllerViewSubclass
            addToScrollViewNewController(controller2)
        }
    
        // The main method, adds the controller in the scrollView at the left of the previous controller added
        func addToScrollViewNewController(controller: UIViewController) {
            self.addChildViewController(controller)
    
            contentView.addSubview(controller.view)
    
            controller.view.setTranslatesAutoresizingMaskIntoConstraints(false)
    
            // Setting all the constraints 
            let bottomConstraint = NSLayoutConstraint(item: contentView, attribute: .Bottom, relatedBy: .Equal, toItem: controller.view, attribute: .Bottom, multiplier: 1.0, constant: 0)
    
            let topConstraint = NSLayoutConstraint(item: contentView, attribute: .Top, relatedBy: .Equal, toItem: controller.view, attribute: .Top, multiplier: 1.0, constant: 0)
    
            let widthConstraint = NSLayoutConstraint(item: controller.view, attribute: .Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0)
    
            var trailingConstraint: NSLayoutConstraint!
            if controllers.isEmpty {
                // Since it's the first one, the trailing constraint is from the controller view to the contentView
                trailingConstraint = NSLayoutConstraint(item: contentView, attribute: .Trailing, relatedBy: .Equal, toItem: controller.view, attribute: .Trailing, multiplier: 1.0, constant: 0)
            }
            else {
                trailingConstraint = NSLayoutConstraint(item: controllers.last!.view, attribute: .Leading, relatedBy: .Equal, toItem: controller.view, attribute: .Trailing, multiplier: 1.0, constant: 0)
            }
    
            // Setting the new width constraint of the contentView
            view.removeConstraint(contentViewConstraint)
            contentViewConstraint = computedContentViewConstraint
    
            // Adding all the constraints to the view hierarchy
            view.addConstraint(contentViewConstraint)
            contentView.addConstraints([bottomConstraint, topConstraint, trailingConstraint])
            scrollView.addConstraints([widthConstraint])
    
            controller.didMoveToParentViewController(self)
    
            // Finally adding the controller in the list of controllers
            controllers.append(controller)
        }  
    }
    

    I've used the lbrendanl's version in the past. Now I prefer this one. Let me know what you think of it.

提交回复
热议问题