动画期间错误的帧值
Wrong frame values during animation
我想制作一个类似 iOS 主屏幕文件夹的动画。我在主视图控制器中有一个容器视图,在容器视图中,我使用动画在两个视图控制器之间切换。
这是主视图控制器的代码 Class:
class MainContainerViewController: UIViewController {
@IBOutlet weak var containerView: UIView!
let duration = 1.0
var presenting = true
var originFrame = CGRect.zero
var indexPathSelectedCell: IndexPath?
var dismissCompletion: (()->())?
func cycle(fromViewController: UIViewController, toViewController: UIViewController) {
let folderViewC = (presenting ? fromViewController : toViewController) as! ViewController
let projectViewC = (presenting ? toViewController : fromViewController) as! ProjectViewController
let cellView = (presenting ? (folderViewC.folderCollectionView.cellForItem(at: folderViewC.folderCollectionView.indexPathsForSelectedItems!.first!) as! FolderCollectionViewCell).folderView : projectViewC.containerView)!
let cellSnapshot = cellView.snapshotView(afterScreenUpdates: false)!
let cellFrame = containerView.convert(cellView.frame, from: cellView.superview)
cellSnapshot.frame = cellFrame
cellView.isHidden = true
toViewController.view.frame = self.containerView.frame
toViewController.view.layoutIfNeeded()
toViewController.view.alpha = 0
presenting ? (projectViewC.containerView.isHidden = true) : ((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.isHidden = true)
fromViewController.willMove(toParentViewController: nil)
self.addChildViewController(toViewController)
self.containerView.addSubview(toViewController.view)
self.containerView.addSubview(cellSnapshot)
UIView.animate(withDuration: duration, animations: {
toViewController.view.alpha = 1.0
let finalFrame = self.presenting ? projectViewC.containerView.frame : self.containerView.convert((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.frame, from: (folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.superview)
cellSnapshot.frame = finalFrame
}) { (_) in
if !self.presenting {
self.dismissCompletion?()
}
self.presenting ? (projectViewC.containerView.isHidden = false) : ((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.isHidden = false)
cellSnapshot.removeFromSuperview()
fromViewController.view.removeFromSuperview()
fromViewController.removeFromParentViewController()
toViewController.didMove(toParentViewController: nil)
}
}
}
除 let finalFrame = self.presenting ? projectViewC.containerView.frame : self.containerView.convert((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.frame, from: (folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.superview)
将 finalFrame
设置为错误值外,所有代码均正常工作:
- 当它呈现时,快照会出现在屏幕中间
- 当它解散时,快照会靠近他正确的位置。
let finalFrame = self.presenting ? projectViewC.containerView.frame : self.containerView.convert((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.frame, from: (folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.superview)
行是这样工作的:
- 检查它是否正在呈现
- 如果它正在呈现,请将常量设置为最终 folder view
的 frame 值
- 如果取消转换所选集合视图单元格的 folderView 的 frame 值从该 folderView
的超级视图
由于您在 projectViewController 中对 containerView 的大小使用自动布局,因此您需要在这部分代码之后在 self.containerView
上调用 layoutIfNeeded()
:
self.addChildViewController(toViewController)
self.containerView.addSubview(toViewController.view)
self.containerView.addSubview(cellSnapshot)
所以变成:
self.addChildViewController(toViewController)
self.containerView.addSubview(toViewController.view)
self.containerView.addSubview(cellSnapshot)
self.containerView.layoutIfNeeded()
我想制作一个类似 iOS 主屏幕文件夹的动画。我在主视图控制器中有一个容器视图,在容器视图中,我使用动画在两个视图控制器之间切换。
这是主视图控制器的代码 Class:
class MainContainerViewController: UIViewController {
@IBOutlet weak var containerView: UIView!
let duration = 1.0
var presenting = true
var originFrame = CGRect.zero
var indexPathSelectedCell: IndexPath?
var dismissCompletion: (()->())?
func cycle(fromViewController: UIViewController, toViewController: UIViewController) {
let folderViewC = (presenting ? fromViewController : toViewController) as! ViewController
let projectViewC = (presenting ? toViewController : fromViewController) as! ProjectViewController
let cellView = (presenting ? (folderViewC.folderCollectionView.cellForItem(at: folderViewC.folderCollectionView.indexPathsForSelectedItems!.first!) as! FolderCollectionViewCell).folderView : projectViewC.containerView)!
let cellSnapshot = cellView.snapshotView(afterScreenUpdates: false)!
let cellFrame = containerView.convert(cellView.frame, from: cellView.superview)
cellSnapshot.frame = cellFrame
cellView.isHidden = true
toViewController.view.frame = self.containerView.frame
toViewController.view.layoutIfNeeded()
toViewController.view.alpha = 0
presenting ? (projectViewC.containerView.isHidden = true) : ((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.isHidden = true)
fromViewController.willMove(toParentViewController: nil)
self.addChildViewController(toViewController)
self.containerView.addSubview(toViewController.view)
self.containerView.addSubview(cellSnapshot)
UIView.animate(withDuration: duration, animations: {
toViewController.view.alpha = 1.0
let finalFrame = self.presenting ? projectViewC.containerView.frame : self.containerView.convert((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.frame, from: (folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.superview)
cellSnapshot.frame = finalFrame
}) { (_) in
if !self.presenting {
self.dismissCompletion?()
}
self.presenting ? (projectViewC.containerView.isHidden = false) : ((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.isHidden = false)
cellSnapshot.removeFromSuperview()
fromViewController.view.removeFromSuperview()
fromViewController.removeFromParentViewController()
toViewController.didMove(toParentViewController: nil)
}
}
}
除 let finalFrame = self.presenting ? projectViewC.containerView.frame : self.containerView.convert((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.frame, from: (folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.superview)
将 finalFrame
设置为错误值外,所有代码均正常工作:
- 当它呈现时,快照会出现在屏幕中间
- 当它解散时,快照会靠近他正确的位置。
let finalFrame = self.presenting ? projectViewC.containerView.frame : self.containerView.convert((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.frame, from: (folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.superview)
行是这样工作的:
- 检查它是否正在呈现
- 如果它正在呈现,请将常量设置为最终 folder view 的 frame 值
- 如果取消转换所选集合视图单元格的 folderView 的 frame 值从该 folderView 的超级视图
由于您在 projectViewController 中对 containerView 的大小使用自动布局,因此您需要在这部分代码之后在 self.containerView
上调用 layoutIfNeeded()
:
self.addChildViewController(toViewController) self.containerView.addSubview(toViewController.view) self.containerView.addSubview(cellSnapshot)
所以变成:
self.addChildViewController(toViewController)
self.containerView.addSubview(toViewController.view)
self.containerView.addSubview(cellSnapshot)
self.containerView.layoutIfNeeded()