作者:Glow技術團隊 leo
升級到iOS 9以後,發現新的task switcher的動畫蠻有趣的,於是就動手實現了下,最終效果如下~

思路
1. 首先我們需要一個橫向的scroll view,可以用UICollectionView,也可以自己實現一個。scroll view裡每一頁都是一張card,一屏5張card:
| | |card card card card card| | |
2. 其次,我們需要在scrollViewDidScroll中判斷每張card距離中心的距離,根據這個值來調整它的alpha,scale以及x軸的translation。
alpha:右邊的card alpha都是1,左邊的越靠左alpha越小
scale: 從左往右依次變大
translation:除了中間的card,所有的card都會右偏,而為了讓中間card大部分都露出來,右邊的card偏移需要比左邊大
開工
1. 橫向滾動的scroll view
我們可以自己實現一個橫向無限滾動的scroll view, 具體可以參考: http://tech.glowing.com/cn/practice-in-uiscrollview/
在scrollViewDidScroll中,我們提供一個delegate方法,告訴使用者每一頁距離中心的位置,以便apply各種transform到這個view上,delegate方法如下:
@protocol InfiniteScrollViewDelegate 《NSObject》//請將《》改為英文 - (void)updateView:(UIView *)view withProgress:(CGFloat)progress scrollDirection:(ScrollDirection)direction; @end
說明一下progress的含義,如果一屏有5個visible views的話,那麼它的值會從-2變化到2:
| | |-2...-1...0...1...2| | |
2. 根據每一頁的位置來設置它的transform
首先是alpha,中心右邊的card alpha都是1,而左邊的會越來越淡,所以我們可以這樣寫:
if (progress >= 0) {
view.alpha = 1;
} else {
view.alpha = 1 - fabs(progress) * 0.2;
}其次是scale,由左往右依次變大:
CGAffineTransform transform = CGAffineTransformIdentity; CGFloat scale = 1 + (progress) * 0.03; transform = CGAffineTransformScale(transform, scale, scale);
最後是x軸的translation,除了中間的card,所有的card都會往右偏,而為了讓中間card大部分都露出來,右邊的card偏移需要比左邊大
CGFloat translation = 0;
if (progress > 0) {
translation = fabs(progress) * SCREEN_WIDTH / 2.2;
} else {
translation = fabs(progress) * SCREEN_WIDTH / 15;
}
transform = CGAffineTransformTranslate(transform, translation, 0);完整的實現:
- (void)updateView:(UIView *)view withProgress:(CGFloat)progress scrollDirection:(ScrollDirection)direction
{
// adjust z-index of each views
NSMutableArray *views = [[self.scrollView allViews] mutableCopy];
[views sortUsingComparator:^NSComparisonResult(UIView *view1, UIView *view2) {
return view1.tag > view2.tag;
}];
for (UIView *view in views) {
[view.superview bringSubviewToFront:view];
}
// alpha
if (progress >= 0) {
view.alpha = 1;
} else {
view.alpha = 1 - fabs(progress) * 0.2;
}
CGAffineTransform transform = CGAffineTransformIdentity;
// scale
CGFloat scale = 1 + (progress) * 0.03;
transform = CGAffineTransformScale(transform, scale, scale);
// translation
CGFloat translation = 0;
if (progress > 0) {
translation = fabs(progress) * SCREEN_WIDTH / 2.2;
} else {
translation = fabs(progress) * SCREEN_WIDTH / 15;
}
transform = CGAffineTransformTranslate(transform, translation, 0);
view.transform = transform;
}最後是完整的demo代碼:https://github.com/Glow-Inc/TaskSwitcherDemo