ios 在 Xcode 6 和 Swift 中的视图之间类似 Snapchat 的滑动导航)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24687140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:19:39  来源:igfitidea点击:

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

iosxcodeswiftswipesnapchat

提问by maxster256

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 even close to the Snapchat's nav.

我一直在尝试使用滑动手势识别器和嵌入的导航控制器在我的应用程序中的视图控制器之间实现滑动导航,但它看起来甚至与 Snapchat 的导航都不接近。

What would be the most efficient and appropiate way to implement such functionality?

实现此类功能的最有效和最合适的方法是什么?

I'm quite a newbie to Swift and programming really, and I would appreciate every helpful comment.

我真的是 Swift 和编程的新手,我会很感激每一个有用的评论。

回答by lbrendanl

The short version is to use a container view controller with a scrollview inside the controller. You then create separate view controllers for each screen you want in the application, and make those view controllers' parent the container view controller.

简短版本是在控制器内部使用带有滚动视图的容器视图控制器。然后,您为应用程序中所需的每个屏幕创建单独的视图控制器,并使这些视图控制器的父级成为容器视图控制器。

A github repo with sample code can be found, here.

可以在此处找到带有示例代码的 github 存储库。

回答by cwRichardKim

You need a pageviewcontroller. This was originally for showing tutorials and stuff but you can put view controllers in there as well. There are tons of tutorials out there and essentially you have to apply a little bit of logic to tell the program what view controller to show it next.

您需要一个页面视图控制器。这最初是为了展示教程和东西,但你也可以把视图控制器放在那里。那里有大量的教程,基本上你必须应用一些逻辑来告诉程序接下来要显示哪个视图控制器。

This is a pretty advanced example, but it might be of help to you:

这是一个非常高级的示例,但它可能对您有所帮助:

https://github.com/cwRichardKim/RKSwipeBetweenViewControllers

https://github.com/cwRichardKim/RKSwipeBetweenViewControllers

回答by GaétanZ

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 :

我不喜欢 lbrendanl 给出的版本,因为它不使用约束。我们不能像我们想要的那样定制它。这是相同的版本,但有限制:

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

scrollView 是一个固定到控制器的 IBOutlet,有 4 个约束,控制器视图的每一侧都有一个常量为 0。

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.

contentView 也是一个 IBOutlet,作为 scrollView 的子视图添加到带有 4 个约束的 scrollView 上,每边的常量都为 0。它还具有等高约束和等宽约束。宽度相等约束在运行时被移除,仅用于让 IB 平静下来。这个视图代表了 scrollView 的 contentView。

UPDATE iOS 9

更新 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.

我过去使用过 lbrendanl 的版本。现在我更喜欢这个。告诉我你对它的想法。

回答by Esqarrouth

I suggest using UIPageViewController and hiding the dots bar by deleting these methods:

我建议使用 UIPageViewController 并通过删除这些方法来隐藏点栏:

presentationCountForPageViewController
presentationIndexForPageViewController

Here is a good tutorial:

这是一个很好的教程:

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

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

Here is a great repo for this:

这是一个很好的回购:

https://github.com/goktugyil/EZSwipeController

https://github.com/goktugyil/EZSwipeController

回答by zgorawski

I had similar requirement, initially implemented with PageController, but later I've changed it to UICollectionViewwhere each cell is fullscreen and scroll is set to horizontal.

我有类似的要求,最初是用 实现的PageController,但后来我将其更改为UICollectionView每个单元格全屏显示并且滚动设置为水平。

回答by user3871275

Paged Scroll View, not a PageViewController in the case of Snapchat.

分页滚动视图,而不是 Snapchat 中的 PageViewController。

回答by Steve Sahayadarlin

You can try using CATransitionto create the swiping animation. Here is an example of how you can swipe from one view to another:

您可以尝试使用CATransition来创建滑动动画。以下是如何从一个视图滑动到另一个视图的示例:

    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"];

I found some of that code here:How can I implement a swiping/sliding animation between views?

我在这里找到了一些代码:如何在视图之间实现滑动/滑动动画?