web-dev-qa-db-fra.com

Navigation par balayage de type Snapchat entre les vues dans Xcode 6 et Swift)

J'ai essayé d'implémenter la navigation par balayage entre les contrôleurs de vue dans mon application à l'aide de la reconnaissance du geste de balayage et du contrôleur de navigation intégré, mais cela ne semble même pas proche de la navigation de Snapchat.

Quelle serait la manière la plus efficace et la plus appropriée de mettre en œuvre une telle fonctionnalité?

Je suis assez novice pour Swift et la programmation vraiment, et j'apprécierais tous les commentaires utiles.

17
maxster256

La version courte consiste à utiliser un contrôleur de vue de conteneur avec une vue de défilement à l'intérieur du contrôleur. Vous créez ensuite des contrôleurs de vue distincts pour chaque écran de votre choix dans l'application, et vous faites du parent de ces contrôleurs de vue le contrôleur de vue du conteneur.

Un dépôt github avec un exemple de code peut être trouvé, ici .

20
lbrendanl

Vous avez besoin d'un contrôleur de visualisation de page. C'était à l'origine pour montrer des tutoriels et d'autres choses, mais vous pouvez également y placer des contrôleurs de vue. Il existe des tonnes de tutoriels et vous devez essentiellement appliquer un peu de logique pour indiquer au programme quelle vue le contrôleur doit afficher ensuite.

Ceci est un exemple assez avancé, mais il pourrait vous être utile:

https://github.com/cwRichardKim/RKSwipeBetweenViewControllers

8
cwRichardKim

Je n'aime pas la version donnée par lbrendanl car elle n'utilise pas de contraintes. Nous ne pouvons pas le personnaliser comme nous le voulons. Voici la même version mais avec des contraintes:

scrollView est une IBOutlet attachée au contrôleur avec 4 contraintes avec une constante à 0 de chaque côté à la vue du contrôleur.

contentView est également un IBOutlet ajouté en tant que sous-vue de scrollView épinglé à scrollView avec 4 contraintes avec une constante à 0 de chaque côté. Il a également une contrainte de hauteur égale et une contrainte de largeur égale. La contrainte d'égalité de largeur est supprimée lors de l'exécution et ne sert qu'à calmer IB. Cette vue représente le contentView du scrollView.

METTRE À JOUR 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
}

RÉPONSE PRÉCÉDENTE

    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)
    }  
}

J'ai utilisé la version de lbrendanl dans le passé. Maintenant, je préfère celui-ci. Faites-moi savoir ce que vous en pensez.

4
GaétanZ

Je suggère d'utiliser UIPageViewController et de masquer la barre de points en supprimant ces méthodes:

presentationCountForPageViewController
presentationIndexForPageViewController

Voici un bon tutoriel:

https://www.youtube.com/watch?v=8bltsDG2ENQ

Voici un excellent repo pour cela:

https://github.com/goktugyil/EZSwipeController

3
Esqarrouth

J'avais une exigence similaire, initialement implémentée avec PageController, mais plus tard, je l'ai changé en UICollectionView où chaque cellule est en plein écran et le défilement est défini sur horizontal.

1
zgorawski

Vue de défilement paginée, pas un PageViewController dans le cas de Snapchat.

1
user3871275

Vous pouvez essayer d'utiliser CATransition pour créer l'animation de balayage. Voici un exemple de la façon dont vous pouvez passer d'une vue à une autre:

    UIView *parentView = [self.view superview];

CATransition *animation = [CATransition animation];
[animation setDuration:0.25];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];

[parentView addSubview:yourSecondViewController.view];
[self.view removeFromSuperview];

[[theParentView layer] addAnimation:animation forKey:@"showSecondViewController"];

J'ai trouvé une partie de ce code ici: Comment puis-je implémenter une animation de balayage/glissement entre les vues?

0
Steve Sahayadarlin