在UIPageViewController中获取用户滑动方向

时间:2015-01-13 21:36:57

标签: ios swift uipageviewcontroller

viewControllerBeforeViewController的{​​{1}}和viewControllerAfterViewController这两种方法并不能说明滑动的方向。

UIPageViewControllerDataSource代表的方法transitionCompleted对我们也没有多大帮助。它只是告诉页面是否完全刷过。

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

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

UIPageViewController

我的代码如下所示:

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

根据pbasdf的说法,

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

    }
}
}

6 个答案:

答案 0 :(得分:21)

您应该同时使用willTransitionToViewControllers:didFinishAnimating:委托方法来确定转换是向前还是向后。在课程开头声明几个索引变量,比如currentIndexnextIndexInt)。

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&gt; currentIndex,然后前进;如果nextIndex&lt; 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:)方法中使用。

结束编辑

答案 1 :(得分:1)

假设您有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语句应该不会失败,但以防万一。...

答案 2 :(得分:1)

对于我来说,仅使用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 :(得分:1)

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

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

现在在didFinishAnimating中执行以下操作

func pageViewController(_ pageViewController:UIPageViewController,didFinishAnimating完成:Bool,previousViewControllers:[UIViewController],transitionCompleted完成:Bool){         如果完成了{             return //如果动画未完成则返回         }        让pCont = bottomDataContainer?.viewControllers?[0]为? CustomVC //接受        淘汰目前的VC

    if currentIndex < pCont?.view.tag ?? 0 {
        topNavView.goToNextDate()
    }else{
        topNavView.goToPrevDate()
    }
    selectedIndex = pCont?.view.tag ?? 0
}

答案 4 :(得分:0)

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

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

pageViewController:viewControllerBeforeViewController:

pageViewController:viewControllerAfterViewController:

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

答案 5 :(得分:0)

您可以通过实施 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)
}