Leaves -- iOS上一種圖書翻頁效果的實現1

Leaves -- iOS上一種圖書翻頁效果的實現

Leaves是由Tow Brow開發的一個簡單的圖書翻頁控件,它巧妙地結合了鏡像層、陰影層(用於半透明頁)和漸變層(用於陰影)來實現圖書的翻頁效果。其翻頁效果如下圖所示:
特性
Leaves支持:
文本、圖像、PDF等任何可被渲染到Graphics Context上的對象
通過拖動或點擊來翻頁
支持ipad和iphone大小的顯示區域
Levels目前不支持以下特性
頁面上的交互元素
輕掃動作
 
類和接口
Leaves中主要有三個類:LevelsView、LevelsViewController、LevelsCache:
LevelsCache:是一個輔助類,用於緩存顯示頁。它將顯示的內容緩存爲圖片並保存。
LevelsView:是翻頁視圖,翻頁的主要效果便在些實現。它定義了一系列的層對象,並通過操作這些層對象來實現翻頁中各種效果。
LevelsViewController: LevelsView的控制器
類似於UITableView, LevelsView也有一個相關的數據源類(LeaveViewDataSource)與委託類(LeavesViewDelegate),它們分別有兩個方法,如下所示
複製代碼
@protocol LeavesViewDataSource <NSObject>
- (NSUInteger) numberOfPagesInLeavesView:(LeavesView*)leavesView;
- (void) renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx;
@end
@protocol LeavesViewDelegate <NSObject>
@optional
- (void) leavesView:(LeavesView *)leavesView willTurnToPageAtIndex:(NSUInteger)pageIndex;
- (void) leavesView:(LeavesView *)leavesView didTurnToPageAtIndex:(NSUInteger)pageIndex;
@end
 
層樹結構
LevelsView中的層樹結構如下圖所示:
 
每一個層(Layer)都有其特殊的用途,或作爲內容的顯示層,或作爲陰影層,具體說明如下:
topPage層:顯示當前頁的內容。
topPageOverlay層:在翻頁過程中,該層覆蓋於topPage層上,且顏色偏暗,從而使topPage未翻轉的部分變暗,有陰影的感覺。
topPageShadow層:在翻頁過程中,該層用於表達topPage被翻轉部分所形成的陰影。
topPageReverse層:翻頁過程中,topPage被翻轉部分的反面的容器層。
topPageReverseImage層:反面的內容頁。在豎屏下,用於顯示topPage被翻轉部分的內容,這些內容被映射到該層,給人感覺書是透明的。在橫屏下,顯示的是下一頁的內容。
topPageReverseOverlay層:該層用於覆蓋topPageReverse層,效果與topPageOverlay類似。
topPageReverseShading層:該層在topPageReverse層右側形成一個陰影。
bottomPage層:topPage頁的下一頁所在的層。
bottomPageShadow層:該層爲在翻頁過程中在 bottomPage左側形成的一個陰影層。
leftPage層:該層爲橫屏模式下左側頁所在的層。
leftPageOverlay層:該層覆蓋於爲 leftPage層,效果與topPageOverlay類似。
由上可以看出,層樹中的層主要分爲三類:
內容顯示層:topPage、topPageReverseImage、bottomPage、leftPage
陰影層:topPageShadow、topPageReverseShading、bottomPageShadow
覆蓋層:topPageOverlay、topPageReverseOverlay、leftPageOverlay

圖片緩存
Tow Brow在處理不同的內容(文本、圖像、PDF)時顯示時,所採取的方法是一樣的。他將內容緩存爲圖像,並顯示在屏幕上。基本方法是將內容寫進CGContextRef中,然後根據CGContextRef中的信息創建圖像,具體方法如下:
複製代碼
-(CGImageRef) imageForPageIndex:(NSUInteger)pageIndex {
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate(NULL, 
pageSize.width, 
pageSize.height, 
8, /* bits per component*/
pageSize.width * 4, /* bytes per row */
colorSpace, 
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextClipToRect(context, CGRectMake(0, 0, pageSize.width, pageSize.height));
[dataSource renderPageAtIndex:pageIndex inContext:context];
CGImageRef image = CGBitmapContextCreateImage(context);
CGContextRelease(context);
[UIImage imageWithCGImage:image];
CGImageRelease(image);
return image;
}

當然程序沒有緩存所有頁的內容,而是根據橫豎屏的不同緩存適當數量的內容。每次翻頁時會重新整理緩存中的內容。
翻頁動畫實現
在Leaves中,翻頁的基本原理其實很簡單:翻頁過程中,根據手指的划動來不斷的調整層樹結構中每個層的frame,翻頁結束後,重新調整內容顯示層所顯示的內容。
爲此,LevelsView中設置了一個leafEdge變量,該變量是手指在屏幕上划動時Touch Point在屏幕x軸上的百分比位置,這個操作在touchesMoved:withEvent中完成:
複製代碼
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
......
UITouch *touch = [event.allTouches anyObject];
CGPoint touchPoint = [touch locationInView:self];
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:0.07]
forKey:kCATransactionAnimationDuration];
self.leafEdge = touchPoint.x / self.bounds.size.width;
[CATransaction commit];
}

而在leafEdge的set方法中,我們根據leafEdge的值來重新設定各個Layer的frame屬性
複製代碼
- (void) setLayerFrames {
CGRect rightPageBoundsRect = self.layer.bounds;
CGRect leftHalf, rightHalf;
CGRectDivide(rightPageBoundsRect, &leftHalf, &rightHalf, CGRectGetWidth(rightPageBoundsRect) / 2.0f, CGRectMinXEdge);
if (self.mode == LeavesViewModeFacingPages) {
rightPageBoundsRect = rightHalf;
}
topPage.frame = CGRectMake(rightPageBoundsRect.origin.x, 
rightPageBoundsRect.origin.y, 
leafEdge * rightPageBoundsRect.size.width, 
rightPageBoundsRect.size.height);
topPageReverse.frame = CGRectMake(rightPageBoundsRect.origin.x + (2*leafEdge-1) * rightPageBoundsRect.size.width, 
rightPageBoundsRect.origin.y, 
(1-leafEdge) * rightPageBoundsRect.size.width, 
rightPageBoundsRect.size.height);
......
}

發佈了0 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章