UIPageViewController手动分页无法正常工作。
自动分页工作正常,但当我们手动旋转时,它不能正常工作。
我的ViewController.Swift代码
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var contentView: UIView!
@IBOutlet weak var pageControl: UIPageControl!
let myDataSource = ["Img1", "Img2", "Img3", "Img4"]
let urlDataSource = ["https://fabric.io/", "https://about.gitlab.com/", "https://developer.apple.com/", "https://fast.com/"]
var currentVCIndex = 0
var timer = Timer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
configurePageViewController()
timerStart()
}
func timerStart() {
timer.invalidate()
timer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(configurePageViewController), userInfo: nil, repeats: true)
}
@objc func configurePageViewController() {
guard let pageVc = storyboard?.instantiateViewController(identifier: "CustomPageViewController") as? CustomPageViewController else {
return
}
pageVc.delegate = self
pageVc.dataSource = self
addChild(pageVc)
pageVc.didMove(toParent: self)
pageVc.view.translatesAutoresizingMaskIntoConstraints = false
pageControl.layer.zPosition = 1;
pageControl.numberOfPages = myDataSource.count
pageControl.currentPageIndicatorTintColor = .lightGray
pageControl.pageIndicatorTintColor = .white
contentView.addSubview(pageVc.view)
let views : [String : Any] = ["pageView": pageVc.view!]
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[pageView]-0-|",
options: NSLayoutConstraint.FormatOptions(rawValue: 0),
metrics: nil,
views: views))
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[pageView]-0-|",
options: NSLayoutConstraint.FormatOptions(rawValue: 0),
metrics: nil,
views: views))
guard let startingVc = detailVCAt(index: currentVCIndex) else {
return
}
pageVc.setViewControllers([startingVc], direction: .forward, animated: true)
increaseCount()
}
func increaseCount() {
pageControl.currentPage = currentVCIndex
if currentVCIndex == 3 {
currentVCIndex = 0
} else {
currentVCIndex = currentVCIndex+1
}
}
func detailVCAt(index: Int) -> DataViewController? {
if index >= myDataSource.count || myDataSource.count == 0 {
return nil
}
guard let dataVC = storyboard?.instantiateViewController(identifier: "DataViewController") as? DataViewController else {
return nil
}
dataVC.index = index
dataVC.displayImgName = myDataSource[index]
dataVC.redirectURL = urlDataSource[index]
return dataVC
}
}
extension ViewController: UIPageViewControllerDelegate, UIPageViewControllerDataSource {
func presentationIndex(for _: UIPageViewController) -> Int {
return myDataSource.count
}
func presentationCount(for _: UIPageViewController) -> Int {
return myDataSource.count
}
func pageViewController(_: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let dataVc = viewController as? DataViewController
guard var currentIndex = dataVc?.index else {
return nil
}
currentVCIndex = currentIndex
if currentIndex == 0 {
return nil
}
currentIndex -= 1
pageControl.currentPage = currentVCIndex
// timerStart()
// increaseCount()
return detailVCAt(index: currentIndex)
}
func pageViewController(_: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let dataVc = viewController as? DataViewController
guard var currentIndex = dataVc?.index else {
return nil
}
if currentIndex == myDataSource.count {
return nil
}
currentIndex += 1
currentVCIndex = currentIndex
pageControl.currentPage = currentVCIndex
// timerStart()
// increaseCount()
return detailVCAt(index: currentIndex)
}
}
我的DataViewController.Swift代码
import UIKit
class DataViewController: UIViewController {
@IBOutlet weak var btn: UIButton!
var displayImgName :String?
var redirectURL :String?
var index: Int?
override func viewDidLoad() {
super.viewDidLoad()
btn.setImage(UIImage.init(named: displayImgName ?? ""), for: .normal)
}
@IBAction func onClickBtn(_ sender: UIButton) {
if let url = URL(string: redirectURL ?? ""), UIApplication.shared.canOpenURL(url) {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
}
}
}
我的CustomPageViewController.Swift代码
import UIKit
class CustomPageViewController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
我的StoryBoard图像
发布于 2021-03-08 13:43:09
在您的代码中,currentIndex
正在出错。您可以使用以下委托方法获得正确的currentIndex
。
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
同样,在您预定的计时器中,configurePageViewController
方法每5秒调用一次。此方法在方法调用时创建一个新的UIPageViewController
实例,并添加一个子视图,这将在将来引起内存问题。
我建议您使用故事板将UIPageViewController
嵌入到ContainerView中。你可以找到附加的截图。
我有一个更好的解决方案。请查找以下代码:
我的ViewController.Swift代码:
class ViewController: UIViewController {
@IBOutlet weak var contentView: UIView!
@IBOutlet weak var pageControl: UIPageControl!
let myDataSource = ["Img1", "Img2", "Img3", "Img4"]
let urlDataSource = ["https://fabric.io/", "https://about.gitlab.com/", "https://developer.apple.com/", "https://fast.com/"]
var timer = Timer()
var pageViewController: CustomPageViewController? {
didSet {
pageViewController?.objViewController = self
}
}
override func viewDidLoad() {
super.viewDidLoad()
configurePageControl()
timerStart()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let pageViewController = segue.destination as? CustomPageViewController {
self.pageViewController = pageViewController
}
}
func pageViewIdexChange(_ index : Int) {
pageControl.currentPage = index
}
func timerStart() {
timer.invalidate()
guard let pageViewController = pageViewController else { return }
timer = Timer.scheduledTimer(timeInterval: 5.0, target: pageViewController, selector: #selector(pageViewController.scrollToNextViewController), userInfo: nil, repeats: true)
}
func configurePageControl() {
pageControl.numberOfPages = myDataSource.count
pageControl.currentPageIndicatorTintColor = .lightGray
pageControl.pageIndicatorTintColor = .white
}
}
我的DataViewController.Swift代码:
class DataViewController: UIViewController {
@IBOutlet weak var btn: UIButton!
var displayImgName :String?
var redirectURL :String?
var index: Int?
override func viewDidLoad() {
super.viewDidLoad()
btn.setImage(UIImage.init(named: displayImgName ?? ""), for: .normal)
view.backgroundColor = .random()
}
@IBAction func onClickBtn(_ sender: UIButton) {
if let url = URL(string: redirectURL ?? ""), UIApplication.shared.canOpenURL(url) {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
}
}
}
我的CustomPageViewController.Swift代码:
import UIKit
class CustomPageViewController: UIPageViewController {
weak var objViewController: ViewController?
var myDataSource: [String] = []
var urlDataSource: [String] = []
var currentIndex = 0
private(set) lazy var orderedViewControllers: [UIViewController] = {
// The view controllers will be shown in this order
var vcs : [DataViewController] = []
for i in 0 ..< myDataSource.count {
vcs.append(detailVCAt(index: i)!)
}
return vcs
}()
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
delegate = self
myDataSource = objViewController?.myDataSource ?? []
urlDataSource = objViewController?.urlDataSource ?? []
if let initialViewController = orderedViewControllers.first {
scrollToViewController(initialViewController)
}
}
func detailVCAt(index: Int) -> DataViewController? {
if index >= myDataSource.count || myDataSource.count == 0 {
return nil
}
guard let dataVC = storyboard?.instantiateViewController(identifier: "DataViewController") as? DataViewController else {
return nil
}
dataVC.index = index
dataVC.displayImgName = myDataSource[index]
dataVC.redirectURL = urlDataSource[index]
return dataVC
}
//MARK: - Methods
@objc func scrollToNextViewController() {
if currentIndex < orderedViewControllers.count - 1 {
scrollToViewController(currentIndex + 1)
} else {
scrollToViewController(0, direction: .forward)
}
}
func scrollToViewController(_ newIndex: Int, direction: UIPageViewController.NavigationDirection? = nil) {
var direction = direction
if let firstViewController = viewControllers?.first,
let currentIndex = orderedViewControllers.firstIndex(of: firstViewController) {
if direction == nil {
direction = newIndex >= currentIndex ? .forward : .reverse
}
let nextViewController = orderedViewControllers[newIndex]
scrollToViewController(nextViewController, direction: direction!)
}
}
func scrollToViewController(_ viewController: UIViewController,
direction: UIPageViewController.NavigationDirection = .forward) {
setViewControllers([viewController],
direction: direction,
animated: true,
completion: { (finished) -> Void in
// Setting the view controller programmatically does not fire
// any delegate methods, so we have to manually notify the
// 'tutorialDelegate' of the new index.
self.notifyTutorialDelegateOfNewIndex()
})
}
private func notifyTutorialDelegateOfNewIndex() {
if let firstViewController = viewControllers?.first,
let index = orderedViewControllers.firstIndex(of: firstViewController) {
currentIndex = index
objViewController?.pageViewIdexChange(index)
}
}
}
// MARK: - UIPageViewControllerDataSource & UIPageViewControllerDelegate
extension CustomPageViewController : UIPageViewControllerDataSource , UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = orderedViewControllers.firstIndex(of: viewController) else {
return nil
}
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 orderedViewControllers.last
}
guard orderedViewControllers.count > previousIndex else {
return nil
}
return orderedViewControllers[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = orderedViewControllers.firstIndex(of: viewController) else {
return nil
}
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 orderedViewControllers.first
}
guard orderedViewControllersCount > nextIndex else {
return nil
}
return orderedViewControllers[nextIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
notifyTutorialDelegateOfNewIndex()
}
}
我的StoryBoard图像
发布于 2021-03-08 13:46:36
代码中的问题是,您无法确定当前可见视图控制器的索引,即pageViewController(_:viewControllerBefore:)
和pageViewController(_:viewControllerAfter:)
函数中的UIPageViewControllerDataSource
,因为这些委托函数每次滚动时可能会被多次调用。
例如,如果您当前处于索引0中,并且滚动到索引1,则pageViewController(_:viewControllerAfter:)
函数将被调用2次,一次用于索引1,另一次用于索引2预加载下一页。
尽管如此,您几乎可以在this应答之后查找当前可见视图控制器的索引,并使用UIPageViewControllerDelegate
的pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)
函数,但只需进行一项适合您的需要的小修改:
extension ViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
guard
completed,
let currentIndex = (viewControllers?.first as? DataViewController)?.index
else {
return
}
currentVCIndex = currentIndex
pageControl.currentPage = currentVCIndex
}
}
此外,不需要实现presentationIndex(for:)
和presentationCount(for:)
函数的UIPageViewControllerDataSource
,因为您使用的是自定义UIPageControl
。因此,您的分机可能如下所示:
extension ViewController: UIPageViewControllerDataSource {
func pageViewController(_: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let dataVc = viewController as? DataViewController
guard var currentIndex = dataVc?.index else {
return nil
}
if currentIndex == 0 {
return nil
}
currentIndex -= 1
return detailVCAt(index: currentIndex)
}
func pageViewController(_: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let dataVc = viewController as? DataViewController
guard var currentIndex = dataVc?.index else {
return nil
}
if currentIndex == myDataSource.count {
return nil
}
currentIndex += 1
return detailVCAt(index: currentIndex)
}
}
https://stackoverflow.com/questions/66490580
复制相似问题