ios開發——仿新版iBooks書本開啟與關閉動畫,iosibooks
IOS新版iBooks迷人的地方除了有乾淨整潔的介面、方便靈活的操作以及大容量的書籍容量以外,還有其優秀的使用者互動,尤其是其動畫的使用。開啟一本書時書本緩慢放大並開啟,關閉一本書後書本關閉並回到原位置。現在我們來實現這個簡單的功能。
:
用到的知識:
1、CAKeyframeAnimation的應用
2、如何在代理中區分兩個不同的動畫
3、座標系轉換
思路:
這個動畫主要用到的是CAAnimation,並且是CAKeyframeAnimation,當使用者點擊書本時,設定一個UIImageView(為其加上tag方便以後取)並將其放在選中書本的位置上(使用座標系轉換),接著通過動畫將其放大到全屏,完成後將其錨點設定為(0,0.5)並讓其繞y軸選中π/2角度,將早已放在下面的textView(本app中是自訂的readView)展示出來。動畫完成後將UIImageView的透明度設為0。這樣就是書本的開啟過程。關閉過程類似,根據tag取出UIImageView並將其旋轉,然後設定frame到原來書本的位置(可以用私人變數記錄該位置),最後removeFromSuperview即可。
代碼:
首先是“準備階段”
//BookReadView是展示textView和頂部底部附加view的自訂view CYZBookItemView *itemView = [notification object]; CYZBookReadView *readView = [[CYZBookReadView alloc] initWithFrame:CGRectMake(0, 0, self.view.width, self.view.height) ItemView:itemView]; //設定delegate是為了當使用者從閱讀介面返回時做出響應 readView.delegate = self; //先將其alpha設為0防止使用者剛點擊書本動畫還在進行中時就出現這一介面 readView.alpha = 0.0f; [self.view addSubview:readView]; //展示動畫的UIImageView UIImageView *showView = [[UIImageView alloc] initWithImage:itemView.bookImage.currentBackgroundImage]; //座標系轉換 _itemPosition = [itemView.superview convertRect:itemView.frame toView:self.view]; showView.frame = _itemPosition; //設定tag方便以後取出 showView.tag = 1001; showView.backgroundColor = [UIColor clearColor]; [self.view addSubview:showView];
關於座標系轉換(以矩形為例,point類似):
- (void)convertRect:toView:方法:
格式[被轉換者所在的View convertRect:被轉換者的frame或bounds toView:轉換到的View];返回在目標View中的rect
例如,將當前視圖的子視圖viewA中的一個imageView轉換到當前視圖。可以如下調用:
[viewA convertRect:viewA.imageView.frame toRect:self.view];
或者[imageView.superView convertRect:imageView.frame toRect:self.view];
其中self指控制器。
- (void)convertRect:fromView:方法:
格式[要轉換到的View convertRect:被轉換者的frame或bounds fromView:被轉換者所在的View];返回在目標View中的rect。
還是上一個例子,可以這樣寫:
[self.view convertRect:viewA.imageView.frame fromView:viewA];
或者[self.view convertRect:imageView.frame fromView:imageView.superView];
其中self指控制器
接著準備工作完成了以後就可以開始動畫了。一下是開啟動畫的部分
[UIView animateWithDuration:0.5f animations:^{ //將UIImageView放大為全屏 showView.frame = self.view.bounds; } completion:^(BOOL finished) { if (finished) { //展示出readView readView.alpha = 1.0f; //設定錨點 showView.layer.anchorPoint = CGPointMake(0, 0.5);#warning 不知道為什麼,不加下面這句話showView會顯示異常:即只顯示一半 showView.frame = CGRectMake(0, 0, showView.width, showView.height); CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; //設定其繞y軸旋轉 animation.keyPath = @"transform.rotation.y"; //設定期間,可以定義一常量來表示 animation.duration = 0.5f; animation.speed = 0.55f; animation.removedOnCompletion = NO; //旋轉π/2度 [animation setValues:[NSArray arrayWithObjects:@0.0f, @-M_PI_2, nil]]; //設定代理便於回調 animation.delegate = self; //這裡必須設定上key,為了接下來區分不同動畫 [showView.layer addAnimation:animation forKey:@"rotateToOpenBook"]; } }];
代碼中注釋已經解釋得比較詳細了,只不過正如warning寫得那樣,本來我是用showView.layer.transform來實現動畫的,這樣會省很多事,比如不用在代理中區分動畫、不用記錄position來在方法間傳值等,不過不知道為什麼showView總是只顯示一半,求解釋╮(╯▽╰)╭
回調中:
[showView setAlpha:0.0f];
將其暫時隱藏,關上書時還要用它。
關上書的動畫大致類似
#pragma mark - CYZBookViewDelegate- (void)readViewDidBackWithItem:(CYZBookItemView *)item{ //取出showView UIImageView *showView = (UIImageView *)[self.view viewWithTag:1001]; //將其顯示出來 showView.alpha = 1.0f; showView.layer.anchorPoint = CGPointMake(0, 0.5f); showView.frame = CGRectMake(0, 0, showView.width, showView.height); CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; animation.keyPath = @"transform.rotation.y"; animation.duration = 0.5f; animation.speed = 0.55f; animation.removedOnCompletion = NO; //反向旋轉 [animation setValues:[NSArray arrayWithObjects:@-M_PI_2, @0, nil]]; animation.delegate = self; //設定不同的key為了區分動畫用 [showView.layer addAnimation:animation forKey:@"rotateToCloseBook"]; }
這裡要用一個不同的key來表示這個動畫。
該動畫的回調:
[UIView animateWithDuration:0.5f animations:^{ showView.frame = _itemPosition; } completion:^(BOOL finished) { [showView removeFromSuperview]; }];
_itemPosition是之前用來記錄轉換的座標的私人變數,這幾行代碼的意思就是讓showView回到書本的位置然後令其消失。
這裡的關鍵問題在於,兩個動畫都用到了回調,如何區分呢?就用我們之前設定的key來區分:
回調的完整代碼:
#pragma mark - AnimationDelegate- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ UIImageView *showView = (UIImageView *)[self.view viewWithTag:1001]; if (flag) { if (showView && [[showView.layer animationForKey:@"rotateToOpenBook"] isEqual:anim]) { [showView setAlpha:0.0f]; } else if (showView && [anim isEqual:[showView.layer animationForKey:@"rotateToCloseBook"]]) { [UIView animateWithDuration:0.5f animations:^{ showView.frame = _itemPosition; } completion:^(BOOL finished) { [showView removeFromSuperview]; }]; } }}通過showView所在層layer的方法 animationForKey:獲得自己設定的動畫,與代理中的anim做比較即可區分。
另外,在stackOverflow上還看到一種方法:用kvc的方法為animation設值,並在代理中通過kvc的方法根據這個鍵取出值並進行判斷,應該也是可以的。
ibooks圖書封面
歡迎一起交流。
ibooks 裡開啟書總是自動彈回案頭
首先要確認IBOOKS軟體正常使用不會自己退出(重裝一下或直接裝別的看書軟體),再把檔案傳進去嘛。