寫在前面的話
我個(gè)人感覺動(dòng)畫其實(shí)并不算難镶摘,但是也不算簡(jiǎn)單姥芥。因?yàn)橛兴囊恍┘记赏闷颉O啾扔诿嫦驅(qū)ο蟮拈_發(fā)(百度搜,替換內(nèi)容)這種可能是有一些難凉唐,因?yàn)樗沁^(guò)程式的庸追,要完整寫一份動(dòng)畫,需要費(fèi)一分心思台囱。
- 難度分析
我對(duì)這篇文章的定位來(lái)說(shuō)淡溯,是給一個(gè)可能剛做界面的新人看,所以可能在結(jié)構(gòu)拆分上有些多(繁瑣)簿训,畢竟剛懂乘法口訣的人不可能很快的反應(yīng)出16 * 16 = 256咱娶。但是同時(shí),畢竟是在做動(dòng)畫强品,會(huì)淡化對(duì)語(yǔ)法膘侮,和一些基本類的使用說(shuō)明。
- 動(dòng)畫拆分
這個(gè)應(yīng)該算是基本功择懂,也就是大象進(jìn)冰箱的事喻喳。很多動(dòng)畫乍一看很酷炫,其實(shí)是有很多基本的動(dòng)畫組合而成的困曙,即便是國(guó)外一些很優(yōu)秀的app上的動(dòng)畫表伦,也很少涉及復(fù)雜算法谦去,基本高中的數(shù)學(xué)知識(shí)就足夠了。
那我們具體說(shuō)上面的這個(gè)動(dòng)畫蹦哼,怎么拆鳄哭。
從整體上來(lái)看,它有一個(gè)滾動(dòng)的效果纲熏,可以用scrollView做妆丘,也可以考慮用collectionView,但是對(duì)于每一個(gè)item,我們觀察到還有后續(xù)的動(dòng)畫局劲,包括這種在切換的時(shí)候勺拣,主item,和側(cè)邊item的大小變化這種。
如果是單純的輪播器那種,scrollView應(yīng)該得心應(yīng)手,但是這種不是說(shuō)不可以窗轩,如果這樣用scrollView的話,你需要自定義大量的東西愤惰,剛好collectionView是可以省很多的事(畢竟collectionView抽象出layout這種東西),基于這樣的考慮我們決定用collectionView實(shí)現(xiàn)這樣滾動(dòng)的效果赘理。
- 實(shí)踐
上面分析的需求確實(shí)是很簡(jiǎn)單宦言,但是我們也要做的有模有樣(考慮到后續(xù)的擴(kuò)展)
我推薦剛開始是按照老三樣來(lái)規(guī)規(guī)矩矩的先寫。
譬如對(duì)于模型商模,我們可能只是單純的放在Assets里面奠旺,但是也先獨(dú)立出來(lái)。
+ (NSArray <CardModel *> *)cardModel {
NSMutableArray *arrM = [NSMutableArray array];
for (NSInteger i = 1; i <= 6; i++) {
CardModel *model = [[CardModel alloc] init];
model.cardPicName = [NSString stringWithFormat:@"%ld",(long)i];
[arrM addObject:model];
}
return arrM.copy;
}
然后開始處理collectionView的東西阻桅。這里面需要考慮基于后續(xù)的復(fù)雜度凉倚,我們把collectionView放在UIView上進(jìn)行處理(好像把UIView做控制器的意思兼都,當(dāng)然嫂沉,它不是)
///collectionView視圖
@property (nonatomic, strong) UICollectionView *collectionView;
///背景毛玻璃圖片
@property (nonatomic, strong) UIImageView *bgView;
///模型數(shù)組
@property (nonatomic, strong) NSArray <CardModel *> *imageArray;
我們?cè)诔跏蓟椒ɡ锩嫘枰龅木褪谦@取模型,初始UI
//初始化背景圖并附加毛玻璃效果
self.BgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:self.imageArray[0].cardPicName]];
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
effectView.frame = self.BgView.bounds;
[self.BgView addSubview:effectView];
//初始化collectionView
CardFlowLayout *layout = [[CardFlowLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, ScreenHeight) collectionViewLayout:layout];
self.collectionView.backgroundView = self.BgView;
self.collectionView.dataSource = self;
[self.collectionView registerClass:[CardCollectionViewCell class] forCellWithReuseIdentifier:CellId];
[self addSubview:self.collectionView];
這上面有個(gè)需要說(shuō)明的地方就是layout,如果你僅僅是簡(jiǎn)單的使用collectionView完成橫/縱向排列這些簡(jiǎn)單的事情扮碧,完全可以把layout直接寫在collectionView里面趟章,而不需要單獨(dú)的去繼承,舉凡是繼承l(wèi)ayout,我們通常是要實(shí)現(xiàn)
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect; // return an array layout attributes instances for all the views in the given rect
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;
類似這些UICollectionViewFlowLayout父類的方法或代理(他們有很強(qiáng)大的功能)慎王,所以我們決定單獨(dú)的繼承l(wèi)ayout蚓土,當(dāng)然,現(xiàn)在它里面只是堆本身屬性的一些賦值
self.itemSize = CGSizeMake(ScreenWidth, ScreenHeight);
self.scrollDirection = UICollectionViewScrollDirectionHorizontal; //水平方向
self.minimumLineSpacing = 0;
我在實(shí)驗(yàn)室的時(shí)候觀察到很多人是很少用collectionView的赖淤,其實(shí)和tableView很相似的蜀漆,我們也需要自定義一個(gè)cell。你可能看著那個(gè)卡片上劃下劃咱旱,還能點(diǎn)進(jìn)去的酷炫的樣子确丢,我們先不考慮绷耍。為什么呢,因?yàn)閯?dòng)畫是協(xié)同的鲜侥,我們盡可能的希望它能在一個(gè)水平線上褂始,進(jìn)行同步進(jìn)行,譬如我們的layout里面對(duì)于Item大小描函,就是上面談到的主崎苗,側(cè)item變化這種更前面的事還沒有考慮,就不要著急去考慮這個(gè)cell內(nèi)部的事情舀寓。所以可以事先的在里面放一個(gè)圖片就好胆数。
- (void)setupUI
{
self.coverImageView = [[UIImageView alloc] init];
//稍稍的精致一下(其實(shí)我是為了看collectionView后面那個(gè)蒙板)
self.coverImageView.layer.cornerRadius = 8; //切個(gè)小圓角
self.coverImageView.layer.masksToBounds = YES;
self.coverImageView.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight);
[self.contentView addSubview:self.coverImageView];
}
- (void)loadData:(NSString *)imageName
{
self.coverImageView.image = [UIImage imageNamed:imageName];
}
這樣在collection的dataSource里面對(duì)接一下就好
CardCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellId forIndexPath:indexPath];
[cell loadData:self.imageArray[indexPath.row].cardPicName];
我把這樣定義為第一部分,很easy,手巧一點(diǎn)的新手也可以盲敲出來(lái)互墓。(這是一個(gè)好習(xí)慣幅慌,都說(shuō)程序員不看過(guò)程的,但是你自己做盡量還是對(duì)簡(jiǎn)單的事情可以做到手到擒來(lái)轰豆,這樣后續(xù)的壓力會(huì)小點(diǎn))胰伍,
在下一篇要做的首先是優(yōu)化代碼結(jié)構(gòu),其次是完成卡片式的切換酸休。