快速滚动 UIPageViewController 阻止 viewcontroller 更新
Posted
技术标签:
【中文标题】快速滚动 UIPageViewController 阻止 viewcontroller 更新【英文标题】:Fast scroll UIPageViewController prevents viewcontroller from updating 【发布时间】:2018-08-23 17:15:49 【问题描述】:我有一个 UIPageviewcontroller,里面有两个控制器。当您滑动到下一个时,我使用 viewController 参数来设置适当的委托。但我体验到,如果你刷得太快,函数 viewControllerAfter 不会正确更新 viewController。最初的滑动应该将视图控制器的索引从 0 更新为 1,但如果滑动太快则不会这样做。
import UIKit
class WizardPageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource
lazy var orderedViewControllers: [UIViewController] =
return [self.newVc(viewController: "intro"),
self.newVc(viewController: "welcome")]
()
var pageControl = UIPageControl()
override func viewDidLoad()
super.viewDidLoad()
self.dataSource = self
self.delegate = self
configurePageControl()
// This sets up the first view that will show up on our page control
if let firstViewController = orderedViewControllers.first
setViewControllers([firstViewController],
direction: .forward,
animated: true,
completion: nil)
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
let pageContentViewController = pageViewController.viewControllers![0]
self.pageControl.currentPage = orderedViewControllers.index(of: pageContentViewController)!
func newVc(viewController: String) -> UIViewController
return UIStoryboard(name: "Wizard", bundle: nil).instantiateViewController(withIdentifier: viewController)
func configurePageControl()
// The total number of pages that are available is based on how many available colors we have.
pageControl = UIPageControl(frame: CGRect(x: 0,y: UIScreen.main.bounds.maxY - 225,width: UIScreen.main.bounds.width,height: 50))
self.pageControl.numberOfPages = orderedViewControllers.count
self.pageControl.currentPage = 0
pageControl.isEnabled = false
//self.pageControl.tintColor = UIColor.black
self.pageControl.pageIndicatorTintColor = UIColor.gray
self.pageControl.currentPageIndicatorTintColor = UIColor(red:0.647, green:0.192, blue:0.216, alpha:1.00)
self.view.addSubview(pageControl)
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController?
guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else
return nil
print(orderedViewControllers.index(of: viewController))
let previousIndex = viewControllerIndex - 1
// User is on the first view controller and swiped left to loop to
// the last view controller.
guard previousIndex >= 0 else
return nil
// Uncommment the line below, remove the line above if you don't want the page control to loop.
// return nil
guard orderedViewControllers.count > previousIndex else
return nil
return orderedViewControllers[previousIndex]
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?
guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else
return nil
print(orderedViewControllers.index(of: viewController)) // Returns 0 is I swipe too fast, otherwise 1
if let vc = orderedViewControllers[viewControllerIndex] as? WelcomeViewController
vc.delegate = self
let nextIndex = viewControllerIndex + 1
let orderedViewControllersCount = orderedViewControllers.count
// User is on the last view controller and swiped right to loop to
// the first view controller.
guard orderedViewControllersCount != nextIndex else
return nil
// Uncommment the line below, remove the line above if you don't want the page control to loop.
// return nil
guard orderedViewControllersCount > nextIndex else
return nil
return orderedViewControllers[nextIndex]
【问题讨论】:
【参考方案1】:我遇到了完全同样的问题。它基本上归结为UIPageViewController
(准确地说是_UIQueuingScrollView
)没有正确更新其视图层次结构。
我注意到UIPageViewController
足够聪明,不会在页面保持不变的情况下添加/删除内容视图(即使它在视图层次结构中的位置错误,它也设法以某种方式处理它,因此对用户来说看起来不错)。这就是为什么我添加了PageTrackingView
来观察内容视图被添加(或不添加)到UIPageViewController
视图层次结构的原因。通过跟踪更改是否发生,我可以通过翻转它来计算当前索引。因此,目前的解决方法对于 仅适用于 2 页来说已经足够了。
class PageTrackingView: UIView
var pageIndexable: PageIndexable?
override func willMove(toSuperview newSuperview: UIView?)
super.willMove(toSuperview: newSuperview)
if var pageIndexable = pageIndexable
let newIndex = (pageIndexable.internalIndex == 0) ? 1 : 0
pageIndexable.internalIndex = newIndex
//Reset pageIndexable so that the index flip is fired only once
pageIndexable = nil
protocol PageIndexable
var internalIndex: Int get set
class PageViewController: UIPageViewController,
UIPageViewControllerDataSource,
UIPageViewControllerDelegate,
PageIndexable
private var supportedViewControllers = [UIViewController]()
internal var internalIndex: Int = 0
didSet
if supportedViewControllers.indices.contains(internalIndex)
//Do something with the actual internalIndex value
else
assertionFailure()
init(transitionStyle style: UIPageViewControllerTransitionStyle = .scroll,
navigationOrientation: UIPageViewControllerNavigationOrientation = .horizontal,
options: [String: Any]? = nil,
viewControllers: [T])
supportedViewControllers = viewControllers
if !supportedViewControllers.isEmpty
let viewController = supportedViewControllers[0]
let trackingView = PageTrackingView(frame: viewController.view.frame)
viewController.view.frame = viewController.view.bounds
trackingView.addSubview(viewController.view)
viewController.view = trackingView
super.init(transitionStyle: style,
navigationOrientation: navigationOrientation,
options: options)
func pageViewController(_ pageViewController: UIPageViewController,
didFinishAnimating finished: Bool,
previousViewControllers: [UIViewController],
transitionCompleted completed: Bool)
if !supportedViewControllers.isEmpty, let trackingView = supportedViewControllers[0].view as? PageTrackingView
trackingView.pageIndexable = self
override func viewDidLoad()
super.viewDidLoad()
delegate = self
datasource = self
【讨论】:
【参考方案2】:func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController?
guard let index = arrayVCs.index(of: viewController) else
return nil
if index == 0
return nil
let prevIndex = abs((index - 1) % arrayVCs.count)
return arrayVCs[prevIndex]
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?
guard let index = arrayVCs.index(of: viewController) else
return nil
if index == arrayVCs.count - 1
return nil
let nextIndex = abs((index + 1) % arrayVCs.count)
return arrayVCs[nextIndex]
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
if let viewController = pageViewController.viewControllers?[0]
guard let index = arrayVCs.index(of: viewController) else
return
self.segment.selectedSegmentIndex = index
试试这个。这对我有用。
【讨论】:
这并不能真正解决我的问题。如果滑动太快,仍然没有设置正确的视图控制器的索引。 @Recusiwe 回答已编辑。请试试这个。这是我的工作。 如果你有更多的控制器作为页面,它是否也可以工作? 我应该在哪里设置委托,就像我的帖子中一样? @Recuwise 只需将您的三个方法替换为方法,并且仅更正数据源其余部分都是正确的以上是关于快速滚动 UIPageViewController 阻止 viewcontroller 更新的主要内容,如果未能解决你的问题,请参考以下文章
在 UIPageViewController 中滚动多个页面会创建白色闪光
ios 5 UIPageViewController 将过渡样式更改为滚动