问题
I made UIPageViewController with datasource array and it's works correctly. But when swiping to right for forwarding call both of After and Before methods.
My codes is here:
import UIKit
class MainPageViewController: UIPageViewController,UIPageViewControllerDataSource {
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
initUPageVC(idx:0,isAnimate:false,direction: UIPageViewControllerNavigationDirection.forward)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController?
{
//PRIVIOUS
let pageContent: MainPageContentViewController = viewController as! MainPageContentViewController
var index = pageContent.index
if ((index == 0) || (index == NSNotFound))
{
return nil
}
index -= 1;
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateMenuBarItemSelectedNotif"), object: index)
return getViewControllerAtIndex(index)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?
{
//NEXT
let pageContent: MainPageContentViewController = viewController as! MainPageContentViewController
print("now n",pageContent.index)
var index = pageContent.index
if (index == NSNotFound)
{
return nil;
}
index += 1;
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateMenuBarItemSelectedNotif"), object: index)
return getViewControllerAtIndex(index)
}
func getViewControllerAtIndex(_ index: Int) -> MainPageContentViewController
{
// Create a new view controller and pass suitable data.
let destinationVC = self.storyboard?.instantiateViewController(withIdentifier: "MainPageContentVCID") as! MainPageContentViewController
destinationVC.index = index
return destinationVC
}
func initUPageVC(idx:Int,isAnimate:Bool,direction:UIPageViewControllerNavigationDirection) {
self.setViewControllers(
[getViewControllerAtIndex(idx)],
direction: direction,
animated: isAnimate, completion: nil)
let destinationVC = self.storyboard?.instantiateViewController(withIdentifier: "MainPageContentVCID") as! MainPageContentViewController
destinationVC.index = idx
}
And child vc code here:
import UIKit
class MainPageContentViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
@IBOutlet var tableView: UITableView!
var dataSource : Array<Item>!
var index:Int = 0
var myStr:String!
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "ItemCellNib", bundle: nil), forCellReuseIdentifier: "ItemCellIdentifier")
prepareData()
}
//MARK: Table View
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCellIdentifier", for: indexPath) as! ItemTableViewCell
let obj = dataSource[indexPath.row]
cell.itemImage.image = UIImage(named:obj.imageName)
cell.selectionStyle = UITableViewCellSelectionStyle.none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let obj = dataSource[indexPath.row]
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "itemHasClickedNotif"), object: obj)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 197
}
func prepareData(){
let obj0 = Item()
let obj1 = Item()
let obj2 = Item()
let obj3 = Item()
if index == 0 {
obj0.ID = 0
obj0.imageName = "dog"
obj1.ID = 1
obj1.imageName = "dog"
obj2.ID = 2
obj2.imageName = "dog"
obj3.ID = 3
obj3.imageName = "dog"
}else if index==1{
obj0.ID = 0
obj0.imageName = "cat"
obj1.ID = 1
obj1.imageName = "cat"
obj2.ID = 2
obj2.imageName = "cat"
obj3.ID = 3
obj3.imageName = "cat"
}else{
obj0.ID = 0
obj0.imageName = "lion"
obj1.ID = 1
obj1.imageName = "lion"
obj2.ID = 2
obj2.imageName = "lion"
obj3.ID = 3
obj3.imageName = "lion"
}
dataSource = [obj0,obj1,obj2,obj3]
tableView.setContentOffset(CGPoint.zero, animated: false)
tableView.reloadData()
}
}
Please help me to fix this problem Thank you.
回答1:
It isn't a problem with the page view controller. It's a problem with your assumptions about when viewControllerBefore
and viewControllerAfter
are called. Your assumptions seem reasonable, but they are wrong, as I will now explain.
You are assuming, for example, that when I am in, say, page 3 and I start to swipe to page 4, viewControllerAfter
is called for page 3 so that you can submit page 4. That is not true. The scroll implementation of page view controller uses caching and lookahead to make scrolling faster. Thus, when you do what I just described, it may be that page 4 has already been cached, and now, when the scroll ends, the PVC will call viewControllerAfter
for page 5, in order to pre-cache it in case you scroll again the same way later. Or, if this is the last page, it may be that nothing will be called at all.
This behavior means that you cannot make any assumptions about when viewControllerBefore
and viewControllerAfter
are called or for what page they are called. But your code, with your use of notifications in those methods, depends upon such assumptions — and those assumptions are wrong, and that is why your code isn't working. Everything seems to you to be off-by-one — because it is.
You might be able to solve the problem by relying for your signals instead on the delegate methods willTransitionTo
and didFinishAnimating
(see the docs on UIPageViewControllerDelegate).
来源:https://stackoverflow.com/questions/42031777/call-both-of-after-and-before-method-in-uipageviewcontroller-when-swim-for-forwa