UIPageController:快速向前翻页然后向后翻页只会更新第一页

3
我有一个类SliderPgaeViewController: UIPageViewController,它使用滚动过渡样式,如下所示:
class SliderPgaeViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource, PlayerUpdatePageControllerDelegate {


var lastPendingIndex: Int = 0
var sliderPageDelegate: SliderPageDelegate? = nil
let playerManager = PlayerManager.getInstance()

override func viewDidLoad() {
    super.viewDidLoad()

    self.dataSource = self
    self.delegate = self
    setViewControllers([createViewController(index: playerManager.getCurrentIndex())!], direction: .forward, animated: true, completion: nil)
    lastPendingIndex = playerManager.getCurrentIndex()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

func presentationCount(for pageViewController: UIPageViewController) -> Int {
    return playerManager.getSongsCount()
}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
    if let vc = viewController as? PlayerImageViewController {
        if (vc.index == 0){
            return nil
        }
        return createViewController(index: vc.index! - 1)
    }
    return nil

}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
    if let vc = viewController as? PlayerImageViewController {
        if (vc.index == playerManager.getSongsCount() - 1){
            return nil
        }
        return createViewController(index: vc.index! + 1)
    }
    return nil
}


func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]){
    if let vc = pendingViewControllers[0] as? PlayerImageViewController {
        self.lastPendingIndex = vc.index!
    }
}

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool,previousViewControllers: [UIViewController],transitionCompleted completed: Bool) {
    print("before completion : \(self.lastPendingIndex)")
    if(completed){
        print("completed : \(self.lastPendingIndex)")
        if (viewControllers?.first as? PlayerImageViewController) != nil {
            sliderPageDelegate?.updateSong(index: self.lastPendingIndex, dir: 0)
        }
    }
}

private func createViewController(index i: Int) -> UIViewController?{
    let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PlayerImageController") as! PlayerImageViewController
    vc.index = i
    vc.image = playerManager.getSong(index: i).image
    return vc
}
...

我正在使用此页面控制器在音乐播放器中显示歌曲的缩略图。当用户翻页时,通过在pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool,previousViewControllers: [UIViewController],transitionCompleted completed: Bool)中调用sliderPageDelegate?.updateSong(index: self.lastPendingIndex, dir: 0)来更改正在播放的歌曲。
当我向前翻页然后立即向后翻页时,页面会正确地翻转(先向前再向后);但是,sliderPageDelegate?.updateSong(index: self.lastPendingIndex, dir: 0)仅在向前翻页时被调用。
因此,如果我们有歌曲列表(A、B、C、......),并且我们当前正在播放歌曲A。当用户向前滑动时,缩略图将更改为B的缩略图,并且播放器将更新歌曲为B。但是,如果向前滑动后很快又向后滑动,则缩略图将更改为A,但歌曲仍为B更新: 如果A具有index = 0,而B具有index = 1,则快速移动A->B->A将打印以下内容:
before completion : 1
before completion : 1
completed : 1

只是好奇,UIPageViewController委托是否真的到达传递completed = true给更新歌曲的委托函数的事件?听起来太简单了,但每次我期望某些事情发生而它没有发生时,这就是我的第一个检查(例如,“封装函数的事件是否实际触发了该条件?”)。 - Archdoog
@Archdoog,请检查更新。我认为它回答了你的问题。 - MrGreen
在你的 viewControllerBeforeviewControllerAfter 代码中,你调用了一个 if let vc = viewController as? PlayerImageViewController。你确定每个 vc 都是 PlayerImageViewController 吗? - Jake
@MrGreen 把所有更新歌曲的逻辑放在更新缩略图的方法中是否有任何影响? - trndjc
1个回答

0

我已经在你的代码中添加了PageControllerDelegate并引入了两个新方法。然后在你的UIPageViewController类中实现这些代理,接着在PlayerImageViewController类中在viewWillAppearviewWillDisappear中调用这两个方法。现在移除你的didFinishAnimation方法,并将那段代码写在viewControllerIsBeingDisplay中。

如果想更深入地了解,请查看此代码。

class PlayerImageViewController: UIViewController {
    var index: Int?
    var image: UIImage?
    weak var delegate: PageControllerDelegate?


    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if let del = self.delegate {
            del.viewControllerIsBeingHide(self)
        }
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if let del = self.delegate {
            del.viewControllerIsBeingDisplay(self)
        }
    }
}
protocol SliderPageDelegate {
    func updateSong(index: Int, dir: Int)
}
protocol PageControllerDelegate {
    func viewControllerIsBeingHide(_ viewController: PlayerImageViewController)
    func viewControllerIsBeingDisplay(_ viewController: PlayerImageViewController)
}
class SliderPgaeViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource, PageControllerDelegate {


    var lastPendingIndex: Int = 0
    var sliderPageDelegate: SliderPageDelegate? = nil

    override func viewDidLoad() {
        super.viewDidLoad()

        self.dataSource = self
        self.delegate = self
        setViewControllers([createViewController(index: playerManager.getCurrentIndex())!], direction: .forward, animated: true, completion: nil)
        lastPendingIndex = playerManager.getCurrentIndex()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func presentationCount(for pageViewController: UIPageViewController) -> Int {
        return playerManager.getSongsCount()
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        if let vc = viewController as? PlayerImageViewController {
            if (vc.index == 0){
                return nil
            }
            return createViewController(index: vc.index! - 1)
        }
        return nil

    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        if let vc = viewController as? PlayerImageViewController {
            if (vc.index == playerManager.getSongsCount() - 1){
                return nil
            }
            return createViewController(index: vc.index! + 1)
        }
        return nil
    }


    func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]){
        if let vc = pendingViewControllers[0] as? PlayerImageViewController {
            self.lastPendingIndex = vc.index!
        }
    }


    private func createViewController(index i: Int) -> UIViewController?{
        let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PlayerImageController") as! PlayerImageViewController
        vc.index = i
        vc.delegate = self
//        vc.image = playerManager.getSong(index: i).image //Commented becoz i do not have this file
        return vc
    }
    var previousVCIndex = 0

    func viewControllerIsBeingHide(_ viewController: PlayerImageViewController) {
        previousVCIndex = viewController.index!
    }
    func viewControllerIsBeingDisplay(_ viewController: PlayerImageViewController) {
        if let del = sliderPageDelegate {
            del.updateSong(index: previousVCIndex, dir: 0)
        }
    }
}

问题已经解决。但是 previousVCIndex 的逻辑不正确。我在 viewControllerIsBeingDisplay 中使用了 viewController.index,而完全没有使用 viewControllerIsBeingHide - MrGreen
我认为你可能希望在下一个屏幕中共享一些来自上一个屏幕的信息,这就是我使用previousVCIndex逻辑的原因。 - Syed Qamar Abbas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接