Snapchat-подобная навигационная перемотка между представлениями в Xcode 6 и Swift)
Я пытаюсь реализовать навигацию по навигации между контроллерами View в моем приложении с помощью Sweep Gesture Recognizer и встроенного навигационного контроллера, но он не выглядит даже близко к навигатору Snapchat.
Каким будет наиболее эффективный и подходящий способ реализации таких функций?
Я новичок в Swift и программирую на самом деле, и я был бы признателен за каждый полезный комментарий.
Ответы
Ответ 1
Краткая версия - использовать контроллер представления контейнера со списком прокрутки внутри контроллера. Затем вы создаете отдельные контроллеры представлений для каждого экрана, который вы хотите использовать в приложении, и создавайте родительский элемент контроллера представления для контроллера контейнера.
Здесь можно найти репозиторий github с образцом кода, здесь.
Ответ 2
Вам нужен диспетчер просмотра страницы. Это изначально предназначалось для показа учебных пособий и других материалов, но вы также можете установить контроллеры представлений. Там есть множество учебных пособий, и, по сути, вам нужно применить немного логики, чтобы рассказать программе, какой контроллер просмотра должен показать ее дальше.
Это довольно продвинутый пример, но он может вам помочь:
https://github.com/cwRichardKim/RKSwipeBetweenViewControllers
Ответ 3
Я не люблю версию, данную lbrendanl, потому что она не использует ограничения. Мы не можем настраивать его так, как хотим. Вот такая же версия, но с ограничениями:
scrollView - это IBOutlet, спрятанный контроллером с 4 ограничениями с постоянной до 0 с каждой стороны до вида контроллера.
contentView также является IBOutlet, добавленным как subview scrollView, вычисленным в scrollView с четырьмя ограничениями с константой до 0 с каждой стороны. Он также имеет равное ограничение по высоте и ограничение по ширине. Ограничение ширины равно удаляется во время выполнения и служит только для успокоения IB. Это представление представляет contentView прокрутки.
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
}
ПРЕДЫДУЩИЙ ОТВЕТ
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 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)
}
}
Я использовал версию lbrendanl в прошлом. Теперь я предпочитаю этот. Дайте мне знать, что вы думаете об этом.
Ответ 4
Я предлагаю использовать UIPageViewController и скрывать панель точек, удаляя эти методы:
presentationCountForPageViewController
presentationIndexForPageViewController
Вот хороший учебник:
https://www.youtube.com/watch?v=8bltsDG2ENQ
Вот отличный репо для этого:
https://github.com/goktugyil/EZSwipeController
Ответ 5
Paged Scroll View, а не PageViewController в случае Snapchat.
Ответ 6
Вы можете попробовать использовать 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"];
Я нашел здесь какой-то код: Как реализовать анимацию разворота/скольжения между представлениями?
Ответ 7
У меня было аналогичное требование, первоначально реализованное с помощью PageController
, но позже я изменил его на UICollectionView
, где каждая ячейка полноэкранная, а прокрутка - горизонтальная.