【问题标题】:Get user swiping direction in UIPageViewController在 UIPageViewController 中获取用户滑动方向
【发布时间】:2015-01-13 21:36:56
【问题描述】:

UIPageViewControllerDataSourceviewControllerBeforeViewControllerviewControllerAfterViewController 这两个方法不知道滑动的方向。

UIPageViewController 委托的方法transitionCompleted 也对我们没有多大帮助。它只是告诉页面是否被完全刷过。

那么我应该使用什么方法来准确检测用户方向(左或右)?

这两个属性可能会有所帮助:

let directionForward = UIPageViewControllerNavigationDirection.Forward
let directionReverse = UIPageViewControllerNavigationDirection.Reverse

我的代码如下所示:

import UIKit

class ProView: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

var pageViewController: UIPageViewController?

let characterImages = ["character1", "character2", "character1", "character2", "character1", "character2", "character1", "character2"]

override func viewDidLoad() {
    super.viewDidLoad()
    createPageViewController()
    setupPageControl()

    character = 1
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

// Forward, check if this IS NOT the last controller
func pageViewController(pageViewController: UIPageViewController,
    viewControllerAfterViewController ProView: UIViewController) -> UIViewController? {

        let itemController = ProView as PageItemController

        // Check if there is another view
        if itemController.itemIndex+1 < characterImages.count {

            return getItemController(itemController.itemIndex+1)
        }

        return nil
}


// Check if this IS NOT the first controller
func pageViewController(pageViewController: UIPageViewController,
    viewControllerBeforeViewController ProView: UIViewController) -> UIViewController? {

    let itemController = ProView as PageItemController

        if itemController.itemIndex < 0 {

            return getItemController(itemController.itemIndex-1)
        }

        return nil
}

private func getItemController(itemIndex: Int) -> PageItemController? {

    if itemIndex < characterImages.count {
        let pageItemController = self.storyboard!.instantiateViewControllerWithIdentifier("ItemController") as PageItemController
        pageItemController.itemIndex = itemIndex
        pageItemController.imageName = characterImages[itemIndex]
        return pageItemController
}

    return nil
}

func createPageViewController() {

    let pageController = self.storyboard!.instantiateViewControllerWithIdentifier("PageController") as UIPageViewController
    pageController.dataSource = self
    pageController.delegate = self

    if characterImages.count > 0 {
        let firstController = getItemController(0)!
        let startingViewControllers: NSArray = [firstController]
        pageController.setViewControllers(startingViewControllers, direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
    }

    pageViewController = pageController
    addChildViewController(pageViewController!)
    self.view.addSubview(pageViewController!.view)
    pageViewController?.didMoveToParentViewController(self)
}

func setupPageControl() {
    let appearance = UIPageControl.appearance()
    appearance.pageIndicatorTintColor = UIColor.grayColor()
    appearance.currentPageIndicatorTintColor = UIColor.whiteColor()
}

func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
    return characterImages.count
}

func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {


}

// BETA

func pageViewController(PageItemController: UIPageViewController,
    didFinishAnimating finished: Bool,
    previousViewControllers pageViewController: [AnyObject],
    transitionCompleted completed: Bool)
{

    if (!completed)
    {
        // You do nothing because whatever page you thought
        // the book was on before the gesture started is still the correct page
        return;
    }

    // This is where you would know the page number changed and handle it appropriately

    character = workaround

    }


}

class PageItemController: UIViewController {

@IBOutlet weak var imageCharacterChoose: UIImageView!

var itemIndex: Int = 0
var imageName: String = "" {
    didSet {

        if let imageView = imageCharacterChoose {imageCharacterChoose.image = UIImage(named: imageName)
        }

    }
}
}

根据pbasdf所说,

var currentIndex: Int = 0
var nextIndex: Int = 0

func pageViewController(PageItemController: UIPageViewController,
    willTransitionToViewControllers pageViewController: [AnyObject]) {

        //                          pageViewController is the pending View Controller
        nextIndex = currentIndex

        // pageViewController...... how do I get its index?
}

【问题讨论】:

    标签: ios swift uipageviewcontroller


    【解决方案1】:

    您应该同时使用willTransitionToViewControllers:didFinishAnimating: 委托方法来确定过渡是向前还是向后。在你的课程开始时声明几个索引变量,比如currentIndexnextIndex(都是Int)。

    willTransitionToViewControllers方法中,设置nextIndex等于待处理视图控制器的itemIndex

    编辑

    func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [AnyObject]) {
        // the page view controller is about to transition to a new page, so take note
        // of the index of the page it will display.  (We can't update our currentIndex
        // yet, because the transition might not be completed - we will check in didFinishAnimating:)
        if let itemController = pendingViewControllers[0] as? PageItemController {
            nextIndex = itemController.itemIndex
        }
    }
    

    结束编辑

    此时您可以计算出是向前还是向后过渡:如果nextIndex > currentIndex,则向前;如果 nextIndex currentIndex 则向后。然后在didFinishAnimating 中,如果completed 为真(所以它完成了到下一个视图控制器的转换),将currentIndex 设置为等于nextIndex,这样您就可以在需要指示当前哪个页面的任何地方使用currentIndex在屏幕上:

    编辑

    func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [AnyObject], transitionCompleted completed: Bool) {
        if (completed) {
            // the page view controller has successfully transitioned to the next view
            // controller, so we can update our currentIndex to the value we obtained 
            // in the willTransitionToViewControllers method:
            currentIndex = nextIndex
    
        }
    }
    

    请注意,这些方法的第一个参数是 pageViewController(UIPageViewController 的实例),而不是您当前代码中的 pageItemController

    最后,请注意:您引用的枚举 (UIPageViewControllerNavigationDirection) 仅在 setViewControllers(_, direction:) 方法中使用。

    结束编辑

    【讨论】:

    • 非常感谢您准确回答我的问题。请您解释一下如何获取待处理视图控制器的索引。你说“......等于待处理视图控制器的 itemIndex”,但我知道如何做到这一点。其余的答案很清楚而且很好 - 再次感谢!
    • @CeceXX 我已经用一些示例代码更新了我的答案。
    • 非常感谢!
    • 我想在这里添加。有时您移动到下一个控制器并立即向相反方向滑动。在这种情况下,不会在最后一次滑动时调用“willTransitionToViewControllers”。所以你必须添加: if (completed) { ...} else { nextIndex = previousViewController.index }
    【解决方案2】:

    就我而言,我只能使用func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [AnyObject], transitionCompleted completed: Bool) 来确定滑动方向。

    这里是如何。假设您已经有一种方法可以引用名为currentIndex 的当前索引。在上面的方法中,你已经有了previousViewControllers的信息,这样你就可以得到之前名为previousIndex的索引。

    基本上,这是委托方法内部的实现:

    func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [AnyObject], transitionCompleted completed: Bool) {
      if completed {
        if previousIndex < currentIndex {   // forward
    
        }
        else if previousIndex > currentIndex {  // reverse
    
        }
      }
    }
    

    【讨论】:

      【解决方案3】:

      假设你有一个 ViewControllers 的本地数组,你可以使用这个delegate 方法:

      func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
          guard let current = self.viewControllers?.first else {
              // TODO handle error
              return
          }
      
          guard let index = self.pages.firstIndex(of: current) else {
              // TODO handle error
              return
          }
      
          self.currentIndex = index
      }
      

      guard 语句不应失败,但以防万一......

      【讨论】:

        【解决方案4】:

        首先在您的 viewControllerForIndex 方法中分配 viewcontroller.view.tag = index 以便每个 viewcontroller.view 都有一个分配的值

        有一个 currentIndex 属性,该属性最初分配给您在 pageviewcontroller 中实例化的 viewcontroller 的索引

        现在在 didFinishAnimating 中执行以下操作

        func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
                if !completed {
                    return     // return if animation is not completed
                }
               let pCont = bottomDataContainer?.viewControllers?[0] as? CustomVC   //take 
               out current VC
        
                if currentIndex < pCont?.view.tag ?? 0 {
                    topNavView.goToNextDate()
                }else{
                    topNavView.goToPrevDate()
                }
                selectedIndex = pCont?.view.tag ?? 0
            }
        

        【讨论】:

          【解决方案5】:

          你可以通过实现UIScrollViewDelegate

          var lastScrollDirection: UIPageViewController.NavigationDirection?
          
          func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
            let translation = scrollView.panGestureRecognizer.translation(in: scrollView.superview)
              
            self.lastScrollDirection = translation.x < 0 ? .forward : .reverse
          }
          

          分配委托可能比较棘手。这是我在一个项目中使用的:

          func assignScrollDelegate(rootView: UIView) {
            for view in rootView.subviews {
              if let scrollView = view as? UIScrollView {
                scrollView.delegate = self
              }
              else {
                assignScrollDelegate(rootView: view)
              }
            }
          }
          

          当您有对UIPageViewController 的引用时调用它。例如,当您的控制器加载时:

          override func viewDidLoad() {
            self.assignScrollDelegate(rootView: self.pageController.view)
          }
          

          【讨论】:

          • 这很有帮助,但您可能希望使用 scrollViewDidEndDragging 而不是 scrollViewWillBeginDragging 来更新您的模型
          【解决方案6】:

          无法确定用户是向前还是向后滑动。

          你需要使用这两种方法来提供前后的视图:

          pageViewController:viewControllerBeforeViewController:

          pageViewController:viewControllerAfterViewController:

          您可以通过向 viewControllers 添加属性来跟踪索引,然后您可以比较 pageIndexes。

          【讨论】:

          • 我该怎么做呢? “您可以通过向 viewControllers 添加属性来跟踪索引,然后您可以比较 pageIndexes。”。谢谢!
          • @CeceXX 视图控制器将有一个名为 pageIndex 的属性,如本教程:makemegeek.com/uipageviewcontroller-example-ios
          猜你喜欢
          • 1970-01-01
          • 2015-07-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-25
          • 1970-01-01
          • 2016-08-01
          • 1970-01-01
          相关资源
          最近更新 更多