Ответ 1
Используйте это funtion и задайте стиль перехода для нужной анимации.
У меня есть UIPageViewController, который отлично работает, когда мы проводим влево или вправо, чтобы переворачивать страницы.
class ViewController: UIViewController, UIPageViewControllerDataSource {
...
}
Теперь я намерен также предоставить кнопку "Предыдущая/Следующая" на странице, чтобы можно было перелистывать страницы, нажимая эти кнопки.
Как я могу активировать поведение влево/вправо ИЛИ переворачивать страницы программно?
Это вопрос к языку Swift, а не к Objective-C.
Используйте это funtion и задайте стиль перехода для нужной анимации.
Как правило, нет необходимости возиться с индексами страниц, а что нет. Скорее всего, вы уже реализуете dataSource: UIPageViewControllerDataSource
, у которого есть все, что вам нужно, чтобы отобразить предыдущий или следующий ViewController.
Swift 2.2 Пример:
extension UIPageViewController {
func goToNextPage(){
guard let currentViewController = self.viewControllers?.first else { return }
guard let nextViewController = dataSource?.pageViewController( self, viewControllerAfterViewController: currentViewController ) else { return }
setViewControllers([nextViewController], direction: .Forward, animated: false, completion: nil)
}
func goToPreviousPage(){
guard let currentViewController = self.viewControllers?.first else { return }
guard let previousViewController = dataSource?.pageViewController( self, viewControllerBeforeViewController: currentViewController ) else { return }
setViewControllers([previousViewController], direction: .Reverse, animated: false, completion: nil)
}
}
Таким образом, вы гарантируете, что страницы, на которые вы переходите, - это именно то, что вызовет запуск PageViewController в жестов.
Версия SuitedSloth от Swift 3 (с небольшим изменением animated
параметра, так как мне нужно, чтобы он был анимирован по умолчанию, но все же принимал параметр в функции) на случай, если это кому-нибудь понадобится:
extension UIPageViewController {
func goToNextPage(animated: Bool = true) {
guard let currentViewController = self.viewControllers?.first else { return }
guard let nextViewController = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) else { return }
setViewControllers([nextViewController], direction: .forward, animated: animated, completion: nil)
}
func goToPreviousPage(animated: Bool = true) {
guard let currentViewController = self.viewControllers?.first else { return }
guard let previousViewController = dataSource?.pageViewController(self, viewControllerBefore: currentViewController) else { return }
setViewControllers([previousViewController], direction: .reverse, animated: animated, completion: nil)
}
}
Вот также быстрая реализация 4 с делегатами.
Так как я также использую UIPageViewControllerDelegate, и методы делегата не были вызваны с большинством решений setViewController.
Спасибо Эндрю Дункану за его комментарий о делегате.
// Functions for clicking next and previous in the navbar, Updated for swift 4
@objc func toNextArticle(){
guard let currentViewController = self.viewControllers?.first else { return }
guard let nextViewController = dataSource?.pageViewController( self, viewControllerAfter: currentViewController ) else { return }
// Has to be set like this, since else the delgates for the buttons won't work
setViewControllers([nextViewController], direction: .forward, animated: true, completion: { completed in self.delegate?.pageViewController?(self, didFinishAnimating: true, previousViewControllers: [], transitionCompleted: completed) })
}
@objc func toPreviousArticle(){
guard let currentViewController = self.viewControllers?.first else { return }
guard let previousViewController = dataSource?.pageViewController( self, viewControllerBefore: currentViewController ) else { return }
// Has to be set like this, since else the delgates for the buttons won't work
setViewControllers([previousViewController], direction: .reverse, animated: true, completion:{ completed in self.delegate?.pageViewController?(self, didFinishAnimating: true, previousViewControllers: [], transitionCompleted: completed) })
}
Вот краткая реализация этого:
private func slideToPage(index: Int, completion: (() -> Void)?) {
let count = //Function to get number of viewControllers
if index < count {
if index > currentPageIndex {
if let vc = viewControllerAtIndex(index) {
self.pageViewController.setViewControllers([vc], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: { (complete) -> Void in
self.currentPageIndex = index
completion?()
})
}
} else if index < currentPageIndex {
if let vc = viewControllerAtIndex(index) {
self.pageViewController.setViewControllers([vc], direction: UIPageViewControllerNavigationDirection.Reverse, animated: true, completion: { (complete) -> Void in
self.currentPageIndex = index
completion?()
})
}
}
}
}
viewControllerAtIndex(index: Int) -> UIViewController?
- это моя собственная функция, чтобы получить правильный контроллер просмотра для прокрутки.
Просто оставив это здесь, вы хотите, чтобы кто-то захотел использовать определенный протокол для навигации по нему и с программным изменением контроллеров представления.
@objc protocol AppWalkThroughDelegate {
@objc optional func goNextPage(forwardTo position: Int)
@objc optional func goPreviousPage(fowardTo position: Int)
}
Используйте вышеуказанный протокол и подтвердите root UIPageViewController для управления навигацией между контроллерами представлений.
Пример ниже:
class AppWalkThroughViewController: UIPageViewController, UIPageViewControllerDataSource, AppWalkThroughDelegate {
// Add list of view controllers you want to load
var viewControllerList : [UIViewControllers] = {
let firstViewController = FirstViewController()
let secondViewController = SecondViewController()
// Assign root view controller as first responder
secondViewController.delegate = self
let thirdViewController = ThirdViewController()
}
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
}
// Navigate to next page
func goNextPage(fowardTo position: Int) {
let viewController = self.viewControllerList[position]
setViewControllers([viewController], direction:
UIPageViewControllerNavigationDirection.forward, animated: true, completion: nil)
}
}
После достижения всего этого контроллеры детского представления, которые должны заставить UIPageViewController перемещаться на следующую или предыдущую страницу, могут использовать методы AppWalkThroughDelegate, передав определенный номер в свойство delegate.
Пример ниже: Метод делегата, который вызывается после нажатия кнопки
class SecondViewController: UIViewController {
var delegate: AppWalkThroughDelegate!
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
}
@IBAction func goNextPage(_ sender: Any) {
// Can be any number but not outside viewControllerList bounds
delegate.goNextPage!(fowardTo: 2)
}
}
let orderedViewControllers = [UIViewController(),UIViewController(), UIViewController()]
let pageViewController = UIPageViewController()
let pageControl = UIPageControl()
func jump(to: Int, completion: @escaping (_ vc: UIViewController?) -> Void){
guard orderedViewControllers.count > to else{
//index of bounds
return
}
let toVC = orderedViewControllers[to]
var direction: UIPageViewController.NavigationDirection = .forward
if pageControl.currentPage < to {
direction = .forward;
} else {
direction = .reverse;
}
pageViewController.setViewControllers([toVC], direction: direction, animated: true) { _ in
DispatchQueue.main.async {
self.pageViewController.setViewControllers([toVC], direction: direction, animated: false){ _ in
self.pageControl.currentPage = to
completion(toVC)
}
}
}
}
ИСПОЛЬЗОВАНИЕ:
self.jump(to: 5) { (vc) in
// you can do anything for new vc.
}