作者: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