1

我有一个名为 ProfileCollectionViewController 的集合视图,用于收集图像。单击图像时,它会显示一个 Horizo​​ntalProfileViewController,它会全屏显示图像。在 Horizo​​ntalProfileViewController 上按下后退按钮时,我希望全屏图像动画回 ProfileViewController 中的缩略图。我将 ProfileViewController 中的选定索引路径作为 initialIndexPath 传递给 Horizo​​ntalProfileViewController,以便知道缩略图的位置。下面是我的过渡动画代码

import UIKit

class SEHorizontalFeedToProfile: NSObject, UIViewControllerAnimatedTransitioning {

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        return 0.2
    }

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

        if let profileVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as? SEProfileGridViewController, horizontalFeedVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as? SEProfileHorizontalViewController, containerView = transitionContext.containerView() {
            let duration = transitionDuration(transitionContext)
            profileVC.collectionView?.reloadData()
            if let indexPath = horizontalFeedVC.initialIndexPath {
                let cell = profileVC.collectionView?.cellForItemAtIndexPath(indexPath)
                print(indexPath)
                let imageSnapshot = horizontalFeedVC.view.snapshotViewAfterScreenUpdates(false)
                let snapshotFrame = containerView.convertRect(horizontalFeedVC.view.frame, fromView: horizontalFeedVC.view)
                imageSnapshot.frame = snapshotFrame
                horizontalFeedVC.view.hidden = true

                profileVC.view.frame = transitionContext.finalFrameForViewController(profileVC)
                containerView.insertSubview(profileVC.view, belowSubview: horizontalFeedVC.view)
                containerView.addSubview(imageSnapshot)

                UIView.animateWithDuration(duration, animations: {
                    var cellFrame = CGRectMake(0, 0, 0, 0)
                    if let theFrame = cell?.frame {
                        cellFrame = theFrame
                    }
                    let frame = containerView.convertRect(cellFrame, fromView: profileVC.collectionView)
                    imageSnapshot.frame = frame
                    }, completion: { (succeed) in
                        if succeed {
                            horizontalFeedVC.view.hidden = false
                            //                                cell.contentView.hidden = false
                            imageSnapshot.removeFromSuperview()
                            transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
                        }
                })
            }
        }
    }

}

我放了断点,发现在代码中

let cell = profileVC.collectionView?.cellForItemAtIndexPath(indexPath)

单元格为零。我不明白为什么它会为零。请帮我。我提前谢谢你。

profileVC 是 UICollectionViewController 的子类

PS:请查看以下项目,该项目完全相同,没有任何问题。我试图模仿它,但它对我的不起作用。 https://github.com/PeteC/InteractiveViewControllerTransitions

4

1 回答 1

1

正如对该问题的评论中所指出的,该单元格设置为 nil 因为该单元格不可见。由于您的 Horizo​​ntalProfileViewController 允许滚动到其他图片,因此可以滚动到尚未在 ProfileCollectionViewController 中为其创建 UICollectionViewCell 的图像。

您可以通过滚动到当前图像在 UICollectionView 上的位置来解决此问题。你说那initialIndexPath最初是第一次选择的图像的 indexPath 。假设您在用户滚动到不同的图像时更新它,以便它仍然准确地表示屏幕上图像的 indexPath,如果需要,我们可以使用它来强制 UICollectionView 滚动到当前单元格。

通过对您的代码进行一些调整,这应该会给您带来预期的效果:

import UIKit    

class SEHorizontalFeedToProfile: NSObject, UIViewControllerAnimatedTransitioning {

func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
    return 0.2
}

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

    if let profileVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as? SEProfileGridViewController, horizontalFeedVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as? SEProfileHorizontalViewController, containerView = transitionContext.containerView() {
        let duration = transitionDuration(transitionContext)
        //profileVC.collectionView?.reloadData()  //Remove this

        if let indexPath = horizontalFeedVC.initialIndexPath {
            var cell = profileVC.collectionView?.cellForItemAtIndexPath(indexPath) //make cell a var so it can be reassigned if necessary
            print(indexPath)

            if cell == nil{  //This if block is added. Again it is crucial that initialIndexPath was updated as the user scrolled.
                profileVC.collectionView?.scrollToItemAtIndexPath(horizontalFeedVC.initialIndexPath, atScrollPosition: UICollectionViewScrollPosition.CenteredVertically, animated: false)
                profileVC.collectionView?.layoutIfNeeded() //This is necessary to force the collectionView to layout any necessary new cells after scrolling
                cell = profileVC.collectionView?.cellForItemAtIndexPath(indexPath)
            }
            let imageSnapshot = horizontalFeedVC.view.snapshotViewAfterScreenUpdates(false)
            let snapshotFrame = containerView.convertRect(horizontalFeedVC.view.frame, fromView: horizontalFeedVC.view)
            imageSnapshot.frame = snapshotFrame
            horizontalFeedVC.view.hidden = true

            profileVC.view.frame = transitionContext.finalFrameForViewController(profileVC)
            containerView.insertSubview(profileVC.view, belowSubview: horizontalFeedVC.view)
            containerView.addSubview(imageSnapshot)

            UIView.animateWithDuration(duration, animations: {
                var cellFrame = CGRectMake(0, 0, 0, 0)
                if let theFrame = cell?.frame {
                    cellFrame = theFrame
                }
                let frame = containerView.convertRect(cellFrame, fromView: profileVC.collectionView)
                imageSnapshot.frame = frame
                }, completion: { (succeed) in
                    if succeed {
                        horizontalFeedVC.view.hidden = false
                        //                                cell.contentView.hidden = false
                        imageSnapshot.removeFromSuperview()
                        transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
                    }
            })
        }
    }
}

现在,如果当前 UICollectionViewCell 尚未创建它:

  1. 滚动以使单元格的 indexPath 以视图为中心

  2. 强制 UICollectionView 布局其子视图,从而创建任何必要的 UITableViewCells

  3. 再次请求 UITableViewCell,但这次它不应该是 nil

于 2016-05-16T03:58:36.143 回答