Проблема:
У меня есть мастер UIPageViewController
(MainPageVC
) с тремя встроенными просмотрами страниц (A
, B
, & C
), которые доступны как жестами смахиванияи нажатием соответствующих мест в пользовательском индикаторе страницы * в MainPageVC
(* не является истинным UIPageControl
, но состоит из трех ToggleButton
с - простое повторное воплощение UIButton
, чтобы стать кнопкой переключения).Моя установка выглядит следующим образом:
Предыдущее чтение: Надежный способ отслеживания индекса страницы в UIPageViewController - Swift , Надежный способ получить текущий индекс UIPageViewController и UIPageViewController: вернуть текущее видимое представление , указывающее, что лучший способ сделать это, был вызов didFinishAnimating
и вручную отслеживать текущую страницуиндекс, но я обнаружил, что это не относится к определенным крайним случаям.
Я пытался создать безопасный способ отслеживания текущего индекса страницы (с помощью методов didFinishAnimating
и willTransitionTo
) но у меня возникли проблемы с крайним случаем, когда пользователь видит A
, а затем проводит пальцем до C
(без поднятия пальца), затем за C
, а затем освобождает палец... в этом случае didFinishAnimating
не вызывается, и приложение все еще считает, что оно находится в A
(т. е. кнопка переключения A
все еще нажата, а pageIndex не обновляется корректно viewControllerBefore
and viewControllerAfter
методов).
Мой код:
@IBOutlet weak var pagerView: UIView!
@IBOutlet weak var aButton: ToggleButton!
@IBOutlet weak var bButton: ToggleButton!
@IBOutlet weak var cButton: ToggleButton!
let viewControllerNames = ["aVC", "bVC", "cVC"]
lazy var buttonsArray = {
[aButton, bButton, cButton]
}()
var previousPage = "aVC"
var pageVC: UIPageViewController?
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
print("TESTING - will transition to")
let currentViewControllerClass = String(describing: pageViewController.viewControllers![0].classForCoder);
let viewControllerIndex = viewControllerNames.index(of: currentViewControllerClass);
if currentViewControllerClass == previousPage {
return
}
let pastIndex = viewControllerNames.index(of: previousPage)
if buttonsArray[pastIndex!]?.isOn == true {
buttonsArray[pastIndex!]?.buttonPressed()
}
if let newPageButton = buttonsArray[viewControllerIndex!] {
newPageButton.buttonPressed()
}
self.previousPage = currentViewControllerClass
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
print("TESTING - did finish animating")
let currentViewControllerClass = String(describing: pageViewController.viewControllers![0].classForCoder)
let viewControllerIndex = viewControllerNames.index(of: currentViewControllerClass)
if currentViewControllerClass == previousPage {
return
}
let pastIndex = viewControllerNames.index(of: previousPage)
if buttonsArray[pastIndex!]?.isOn == true {
buttonsArray[pastIndex!]?.buttonPressed()
}
if let newPageButton = buttonsArray[viewControllerIndex!] {
newPageButton.buttonPressed()
}
self.previousPage = currentViewControllerClass
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let onboardingViewControllerClass = String(describing: viewController.classForCoder)
let viewControllerIndex = viewControllerNames.index(of: onboardingViewControllerClass)
let newViewControllerIndex = viewControllerIndex! - 1
if(newViewControllerIndex < 0) {
return nil
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: viewControllerNames[newViewControllerIndex])
if let vc = vc as? BaseTabVC {
vc.mainPageVC = self
vc.intendedCollectionViewHeight = pagerViewHeight
}
return vc
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let onboardingViewControllerClass = String(describing: viewController.classForCoder)
let viewControllerIndex = viewControllerNames.index(of: onboardingViewControllerClass)
let newViewControllerIndex = viewControllerIndex! + 1
if(newViewControllerIndex > viewControllerNames.count - 1) {
return nil
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: viewControllerNames[newViewControllerIndex])
if let vc = vc as? BaseTabVC {
vc.mainPageVC = self
vc.intendedCollectionViewHeight = pagerViewHeight
}
return vc
}
}
Я не знаю, как справиться с этим крайним случаем, проблема в том, что он может привести к летальному исходусбой приложения, если пользователь затем пытается нажать что-то в C
, что в противном случае должно быть гарантировано, и возникает неожиданная ошибка nil
или indexOutOfBounds
.