- 原文链接 : How to Create an iOS Book Open Animation: Part 2
- 原文作者 : Vincent Ngo
- 译文出自 : 开发技术前线 www.devtf.cn
- 译者 : kmyhy
欢迎回到iOS图书动画系列教程!在第一部分,我们学习了如何创建两个自定义的collection view layout并在图书书页中使用了阴影图层以使我们的App显得更加立体和真实。
在这一部分,我们将学习如何创建自定义的转场动画并通过捏放手势来打开一本书。
注意:感谢Attila Hegedüs创建了本教程的示例程序。
本教程以前一部分的内容为基础。如果你还没有看过第一部分,或者想从一个新项目开始,你可以在这里下载上一部分教程中的完整示例程序。
在Xcode中打开项目。现在,你可以选择一本书进行阅读,并从右边滑动进行翻页。这时的转场动画使用的是UINavigationController自带的动画效果。通过本教程的学习,我们将自定义这个动画效果,如下图所示:
这个动画会在“打开书”和“合起书”两个状态之间一一种更加自然的方式平滑过渡,这将更能获得用户的欢心。让我们马上开始吧!
要创建自定义的push动画和pop动画,我们必须创建自定义导航控制器并实现UINavigationControllerDelegate协议。
在App文件夹上右击(或ctrl+左键)并点击New File。选择iOS\Source\Cocoa Touch Class模板并将类名设置为CustomNavigationController。让它继承自UINavigationController并将语言设置为Swift。点击Next,Create。
打开CustomNavigationController.swift,编辑其内容为:
import UIKit
class CustomNavigationController: UINavigationController, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
//1
delegate = self
}
//2
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
if operation == .Push {
return nil
}
if operation == .Pop {
return nil
}
return nil
}
}
上述代码分别解释如下:
现在我们拥有了自己的Navigation Controller类,接下来在故事板中将默认的UINavigationController替换为我们的CustomNavigationController。
打开Main.storyboard,在故事板编辑器左侧的对象窗口中选择Navigation Controller对象,打开Identity窗口,在Custom Class下,将Class由UINavigationController修改为CustomNavigationController,如下图所示:
编译运行,什么变化都没有发生。这是因为在委托方法中我们仍然返回了nil,因此使用的仍然是UINavigationController内置的标准Transition。
最有趣的部分来了——创建我们的自定义Transition对象!:]
要自定义Transition类,我们必须实现UIViewControllerAnimatedTransitioning协议,最主要的是这几个方法:
在App文件夹上右击(或ctrl+左键),然后点击New File。选择iOS\Source\Coca Touch Class 模板,将类名设置为BookOpeningTransition,继承NSObject,语言Swift。然后点击Next,Create。
打开BookOpeningTransition.swift,编辑代码如下:
import UIKit
//1
class BookOpeningTransition: NSObject, UIViewControllerAnimatedTransitioning {
// MARK: Stored properties
var transforms = [UICollectionViewCell: CATransform3D]() //2
var toViewBackgroundColor: UIColor? //3
var isPush = true //4
//5
// MARK: UIViewControllerAnimatedTransitioning
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return 1
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
}
}
以上代码对应注释中的编号,分别解释如下:
定义好需要的变量,接下来就是实现协议方法。
首先是transitionDuration(_:)方法:
if isPush {
return 1
} else {
return 1
}
transitionDuration(_:)方法返回了动画播放时长。这里,无论是Push动画还是Pop动画我们都设置为1秒。通过这个方法我们可以很方便地改变Push动画或Pop动画的时长。
然后,是第二个协议方法——animateTransition——这是最核心的部分!:]我们将这个方法分成两部分来介绍:
回想你在生活中打开一本书的样子:
虽然看起来复杂,但我们只需要考虑两个状态,同时让UIView的animateWithDuration方法根据这两个状态进行不同的处理:
首先,在实现animateTransition(:_)协议方法之前,我们来实现几个助手方法。
仍然在BookOpeningTransition.swift中,编写如下方法:
// MARK: Helper Methods
func makePerspectiveTransform() -> CATransform3D {
var transform = CATransform3DIdentity
transform.m34 = 1.0 / -2000
return transform
}
这个方法返回了一个Transform对象,并在z轴上增加了一点立体感。在播放动画时,我们将用到这个方法。
在makePerspectiveTransform方法后实现如下方法:
func closePageCell(cell : BookPageCell) {
// 1
var transform = self.makePerspectiveTransform()
// 2
if cell.layer.anchorPoint.x == 0 {
// 3
transform = CATransform3DRotate(transform, CGFloat(0), 0, 1, 0)
// 4
transform = CATransform3DTranslate(transform, -0.7 * cell.layer.bounds.width / 2, 0, 0)
// 5
transform = CATransform3DScale(transform, 0.7, 0.7, 1)
}
// 6
else {
// 7
transform = CATransform3DRotate(transform, CGFloat(-M_PI), 0, 1, 0)
// 8
transform = CATransform3DTranslate(transform, 0.7 * cell.layer.bounds.width / 2, 0, 0)
// 9
transform = CATransform3DScale(transform, 0.7, 0.7, 1)
}
//10
cell.layer.transform = transform
}
回想一下BookViewController,它是一个CollectionView,代表了书中的一页。我们将每一页和书脊对齐,以y轴为心进行旋转实现翻页效果。首先,书是合起(关闭)的。这个方法将每个cell(即书页)放平并置于封面的下面。
这是动画运行效果:
以上代码解释如下:
在上面的方法后添加如下方法:
func setStartPositionForPush(fromVC: BooksViewController, toVC: BookViewController) {
// 1
toViewBackgroundColor = fromVC.collectionView?.backgroundColor
toVC.collectionView?.backgroundColor = nil
//2
fromVC.selectedCell()?.alpha = 0
//3
for cell in toVC.collectionView!.visibleCells() as! [BookPageCell] {
//4
transforms[cell] = cell.layer.transform
//5
closePageCell(cell)
cell.updateShadowLayer()
//6
if let indexPath = toVC.collectionView?.indexPathForCell(cell) {
if indexPath.row == 0 {
cell.shadowLayer.opacity = 0
}
}
}
}
setStartPositionForPush(_:toVC:)方法创建状态1的Transition。这个动画涉及到两个ViewController:
fromVC,类型为BooksViewController,用于滚动浏览图书列表。
toVC,BookViewController类型,让你可以翻阅选定的书。
以上代码解释如下: