Ios 从第一页或0索引刷回时如何弹出UIPageViewController?

Ios 从第一页或0索引刷回时如何弹出UIPageViewController?,ios,swipe,uipageviewcontroller,Ios,Swipe,Uipageviewcontroller,我知道刷卡默认由UIPageViewController管理,并且在此过程中调用了一些回调方法,如willtransition,didFinishAnimating等 当我们从第一页或第零个索引刷回时,是否可以关闭UIPageViewController 我检查并发现没有为此操作调用任何回调方法。By designUIPageViewController不知道当前视图控制器索引。每次调用pageViewController(\uquo:viewControllerAfter:)时,您都可以创建U

我知道刷卡默认由
UIPageViewController
管理,并且在此过程中调用了一些回调方法,如
willtransition
didFinishAnimating

当我们从第一页或第零个索引刷回时,是否可以关闭
UIPageViewController


我检查并发现没有为此操作调用任何回调方法。

By design
UIPageViewController
不知道当前视图控制器索引。每次调用
pageViewController(\uquo:viewControllerAfter:)
时,您都可以创建
UIViewController
的新实例,并且向前的页面数将是无限的

我怀疑您向UIPageViewController提供了某种类型的数据源,或者是通过它的数据源,或者是通过
setViewController(uu2;:方向:动画:完成:)
。因此,您有责任跟踪当前显示的
UIViewController
的索引

通过访问
UIPageViewController
的委托中的
previousViewControllers
的第一个元素,可以检查正在显示的视图控制器:

func pageViewController(_ pageViewController: UIPageViewController, 
              didFinishAnimating finished: Bool, 
         previousViewControllers: [UIViewController], 
             transitionCompleted completed: Bool)

按设计
UIPageViewController
不知道当前视图控制器索引。每次调用
pageViewController(\uquo:viewControllerAfter:)
时,您都可以创建
UIViewController
的新实例,并且向前的页面数将是无限的

我怀疑您向UIPageViewController提供了某种类型的数据源,或者是通过它的数据源,或者是通过
setViewController(uu2;:方向:动画:完成:)
。因此,您有责任跟踪当前显示的
UIViewController
的索引

通过访问
UIPageViewController
的委托中的
previousViewControllers
的第一个元素,可以检查正在显示的视图控制器:

func pageViewController(_ pageViewController: UIPageViewController, 
              didFinishAnimating finished: Bool, 
         previousViewControllers: [UIViewController], 
             transitionCompleted completed: Bool)

我能够达到如下预期效果

1) 将以下属性添加到UIPageViewController子类:

var scrollView: UIScrollView?
var swipeBackPanGestureRecognizer: UIPanGestureRecognizer?
2) 现在将以下代码添加到UIPageViewController子类的viewDidLoad方法:

scrollView = view.subviews.filter{ $0 is UIScrollView }.first as? UIScrollView

if let scrollView = scrollView,
   let popGestureRecognizer = self.navigationController?.interactivePopGestureRecognizer,
   let targets = popGestureRecognizer.value(forKey: "targets") as? NSMutableArray {
    let panGestureRecognizer = UIPanGestureRecognizer()
    panGestureRecognizer.setValue(targets, forKey: "targets")
    panGestureRecognizer.delegate = self
    scrollView.addGestureRecognizer(panGestureRecognizer)
    swipeBackPanGestureRecognizer = panGestureRecognizer
}
基本上,您正在向内置scrollView添加一个新的UIPangEstureRecognitor,它从内置InteractivePopEstureRecognitor接管目标操作,负责刷回(我在这里找到了这个提示:)

3) 最后,您需要实现这两种协议方法。确保在UIPageViewController子类的最后一个结束括号下方添加以下代码,并用适当的子类名称替换“YourPageViewController”:

extension YourPageViewController: UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        guard let panRecognizer = gestureRecognizer as? UIPanGestureRecognizer,
            panRecognizer == swipeBackPanGestureRecognizer else {
            return true
        }

        guard let currentViewController = self.viewControllers?.first,
            pageViewController(self, viewControllerBefore: currentViewController) == nil else {
            return false
        }

        guard let gestureView = panRecognizer.view else {
            return true
        }

        let velocity = (panRecognizer.velocity(in: gestureView)).x
        return velocity > 0
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer == swipeBackPanGestureRecognizer && otherGestureRecognizer == scrollView?.panGestureRecognizer {
            return true
        } else {
            return false
        }
    }
}
GestureRecognitizerShouldBegin(:)的实现确保只有当我们在第一页(UIPageViewControllerDataSource viewControllerBefore==nil)上是a)时,以及当我们从左向右(velocity>0)时,我们的回扫手势才会激活


手势识别器(:shouldberredtofailby:)的实现确保了内置UIPageViewController PangestureRecognitor仅在我们自己的回扫手势识别器出现故障时才会触发。

我能够实现如下预期效果

1) 将以下属性添加到UIPageViewController子类:

var scrollView: UIScrollView?
var swipeBackPanGestureRecognizer: UIPanGestureRecognizer?
2) 现在将以下代码添加到UIPageViewController子类的viewDidLoad方法:

scrollView = view.subviews.filter{ $0 is UIScrollView }.first as? UIScrollView

if let scrollView = scrollView,
   let popGestureRecognizer = self.navigationController?.interactivePopGestureRecognizer,
   let targets = popGestureRecognizer.value(forKey: "targets") as? NSMutableArray {
    let panGestureRecognizer = UIPanGestureRecognizer()
    panGestureRecognizer.setValue(targets, forKey: "targets")
    panGestureRecognizer.delegate = self
    scrollView.addGestureRecognizer(panGestureRecognizer)
    swipeBackPanGestureRecognizer = panGestureRecognizer
}
基本上,您正在向内置scrollView添加一个新的UIPangEstureRecognitor,它从内置InteractivePopEstureRecognitor接管目标操作,负责刷回(我在这里找到了这个提示:)

3) 最后,您需要实现这两种协议方法。确保在UIPageViewController子类的最后一个结束括号下方添加以下代码,并用适当的子类名称替换“YourPageViewController”:

extension YourPageViewController: UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        guard let panRecognizer = gestureRecognizer as? UIPanGestureRecognizer,
            panRecognizer == swipeBackPanGestureRecognizer else {
            return true
        }

        guard let currentViewController = self.viewControllers?.first,
            pageViewController(self, viewControllerBefore: currentViewController) == nil else {
            return false
        }

        guard let gestureView = panRecognizer.view else {
            return true
        }

        let velocity = (panRecognizer.velocity(in: gestureView)).x
        return velocity > 0
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer == swipeBackPanGestureRecognizer && otherGestureRecognizer == scrollView?.panGestureRecognizer {
            return true
        } else {
            return false
        }
    }
}
GestureRecognitizerShouldBegin(:)的实现确保只有当我们在第一页(UIPageViewControllerDataSource viewControllerBefore==nil)上是a)时,以及当我们从左向右(velocity>0)时,我们的回扫手势才会激活


gestureRecognizer(:shouldbererequiredTofailby:)的实现确保了内置的UIPageViewController panGestureRecognizer仅在我们自己的回扫手势识别器出现故障时才会触发。

如果您的
UIPageViewController
位于容器视图中,您需要传递
UINavigationController
或在容器的视图控制器中处理它:

override func viewDidLoad() {
    super.viewDidLoad()
    self.delegate = self
    self.dataSource = self
    for view in view.subviews
    {
        if let scrollView = view as? UIScrollView
        {
            scrollView.panGestureRecognizer.require(toFail: self.parentNavController!.interactivePopGestureRecognizer!);
        }
    }
    self.parentNavController!.interactivePopGestureRecognizer!.delegate = self
}

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return self.parentNavController?.topViewController != self.parent || currentIndex == 0
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    switch (segue.identifier) {
        case "pageview_embed":
        let vc = segue.destination as! MyPageViewController
        vc.parentNavController = self.navigationController
        ...
        break
        ...
    }
    ...
}
在容器视图控制器中:

override func viewDidLoad() {
    super.viewDidLoad()
    self.delegate = self
    self.dataSource = self
    for view in view.subviews
    {
        if let scrollView = view as? UIScrollView
        {
            scrollView.panGestureRecognizer.require(toFail: self.parentNavController!.interactivePopGestureRecognizer!);
        }
    }
    self.parentNavController!.interactivePopGestureRecognizer!.delegate = self
}

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return self.parentNavController?.topViewController != self.parent || currentIndex == 0
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    switch (segue.identifier) {
        case "pageview_embed":
        let vc = segue.destination as! MyPageViewController
        vc.parentNavController = self.navigationController
        ...
        break
        ...
    }
    ...
}

如果您的
UIPageViewController
位于容器视图中,则需要传递
UINavigationController
或在容器的视图控制器内处理它:

override func viewDidLoad() {
    super.viewDidLoad()
    self.delegate = self
    self.dataSource = self
    for view in view.subviews
    {
        if let scrollView = view as? UIScrollView
        {
            scrollView.panGestureRecognizer.require(toFail: self.parentNavController!.interactivePopGestureRecognizer!);
        }
    }
    self.parentNavController!.interactivePopGestureRecognizer!.delegate = self
}

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return self.parentNavController?.topViewController != self.parent || currentIndex == 0
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    switch (segue.identifier) {
        case "pageview_embed":
        let vc = segue.destination as! MyPageViewController
        vc.parentNavController = self.navigationController
        ...
        break
        ...
    }
    ...
}
在容器视图控制器中:

override func viewDidLoad() {
    super.viewDidLoad()
    self.delegate = self
    self.dataSource = self
    for view in view.subviews
    {
        if let scrollView = view as? UIScrollView
        {
            scrollView.panGestureRecognizer.require(toFail: self.parentNavController!.interactivePopGestureRecognizer!);
        }
    }
    self.parentNavController!.interactivePopGestureRecognizer!.delegate = self
}

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return self.parentNavController?.topViewController != self.parent || currentIndex == 0
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    switch (segue.identifier) {
        case "pageview_embed":
        let vc = segue.destination as! MyPageViewController
        vc.parentNavController = self.navigationController
        ...
        break
        ...
    }
    ...
}

我已经在跟踪索引了,这里的问题是当我们在UIPageViewController的第一页时,我们向右滑动,那么我们有机会得到那个事件吗?啊,好吧,我完全误解了你的问题。我认为一个解决方案可能是遍历
UIPageViewController
,因为它的内部
UIScrollView
,然后检查内容偏移量,查看用户滚动了多远。哦,酷!我会试试:)谢谢,我已经在跟踪索引了,这里的问题是当我们在UIPageViewController的第一页时,我们向右滑动,那么我们有机会得到那个事件吗?啊,好吧,我完全误解了你的问题。我认为一个解决方案可能是遍历
UIPageViewController
,因为它的内部
UIScrollView
,然后检查内容偏移量,查看用户滚动了多远。哦,酷!我试试看:)谢谢