iOS CollectionView 列表&網(wǎng)格之間切換(帶動(dòng)畫)

原文地址:https://www.hlzhy.com/?p=57

前言:

最近在寫一個(gè)列表界面够傍,這個(gè)列表能夠在列表和網(wǎng)格之間切換,這種需求算是比較常見的挠铲。本以為想我們是站在大牛的肩膀上編程冕屯,就去找了下度娘和谷哥,但是并沒有找到我想要的(找到的都是不帶動(dòng)畫的切換)拂苹。既然做不了VC戰(zhàn)士安聘,那就自己動(dòng)手豐衣足食。在我看來瓢棒,所有的視圖變化都應(yīng)該盡量帶個(gè)簡(jiǎn)單的過渡動(dòng)畫浴韭,當(dāng)然,過度使用華麗的動(dòng)畫效果也會(huì)造成用戶的審美疲勞音羞〈呀埃“動(dòng)畫有風(fēng)險(xiǎn),使用需謹(jǐn)慎”嗅绰。

依稀記得以前面試的時(shí)候被面試官問過這個(gè)問題,并被告知CollectionView自帶有列表和網(wǎng)格之間切換并且?guī)?dòng)畫的API搀继。最終找到如下方法:

/**
Summary
Changes the collection view’s layout and optionally animates the change.

Discussion
This method makes the layout change without further interaction from the user. If you choose to animate the layout change, the animation timing and parameters are controlled by the collection view.
*/
- (void)setCollectionViewLayout:(UICollectionViewLayout *)layout animated:(BOOL)animated; // transition from one layout to another

最終效果(切換動(dòng)畫&動(dòng)畫慢放).gif

實(shí)現(xiàn):

UIViewController.m

一窘面、初始化UICollectionView

在當(dāng)前控制器準(zhǔn)備一個(gè)BOOLisList,用來記錄當(dāng)前選擇的是列表還是網(wǎng)格叽躯,準(zhǔn)備兩個(gè)UICollectionViewFlowLayout對(duì)應(yīng)列表和網(wǎng)格的布局财边,設(shè)置一個(gè)NOTIFIC_N_NAME宏,將此宏作為NotificationName点骑,稍后將以通知的方式通知Cell改變布局酣难。并且初始化UICollectionView谍夭。

@interface ViewController ()<UICollectionViewDelegate, UICollectionViewDataSource>
@property (nonatomic, strong) UICollectionView *myCollectionView;

@property (nonatomic, assign) BOOL isList;
@property (nonatomic, strong) UICollectionViewFlowLayout *gridLayout;
@property (nonatomic, strong) UICollectionViewFlowLayout *listLayout;
@end
#define NOTIFIC_N_NAME @"ViewController_changeList"
@implementation ViewController
-(UICollectionViewFlowLayout *)gridLayout{
    if (!_gridLayout) {
        _gridLayout = [[UICollectionViewFlowLayout alloc] init];
        CGFloat width = (self.view.frame.size.width - 5) * 0.5;
        _gridLayout.itemSize = CGSizeMake(width, 200 + width);
        _gridLayout.minimumLineSpacing = 5;
        _gridLayout.minimumInteritemSpacing = 5;
        _gridLayout.sectionInset = UIEdgeInsetsZero;
    }
    return _gridLayout;
}
-(UICollectionViewFlowLayout *)listLayout{
    if (!_listLayout) {
        _listLayout = [[UICollectionViewFlowLayout alloc] init];
        _listLayout.itemSize = CGSizeMake(self.view.frame.size.width, 190);
        _listLayout.minimumLineSpacing = 0.5;
        _listLayout.sectionInset = UIEdgeInsetsZero;
    }
    return _listLayout;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    _myCollectionView = [[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:self.gridLayout];
    _myCollectionView.showsVerticalScrollIndicator = NO;
    _myCollectionView.backgroundColor = [UIColor grayColor];
    _myCollectionView.delegate = self;
    _myCollectionView.dataSource = self;
    [self.view addSubview:_myCollectionView];
    [self.myCollectionView registerClass:[HYChangeableCell class] forCellWithReuseIdentifier:@"HYChangeableCell"];
    //......
}
二、實(shí)現(xiàn)UICollectionViewDataSource

創(chuàng)建UICollectionViewCell憨募,給cell.isList賦值紧索, 告訴Cell當(dāng)前狀態(tài),給cell.notificationName賦值菜谣,用以接收切換通知珠漂。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    HYChangeableCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HYChangeableCell" forIndexPath:indexPath];
    cell.isList = _isList;
    cell.notificationName = NOTIFIC_N_NAME;
    return cell;
}
三、點(diǎn)擊切換按鈕

通過setCollectionViewLayout:animated:方法重新為CollectionView布局尾膊,并將animated設(shè)為YES媳危。但是僅僅這樣是不夠的,因?yàn)檫@樣并不會(huì)觸發(fā)cellForItemAtIndexPath方法冈敛。我們還需向Cell發(fā)送通知告訴它“你需要改變布局了”待笑。

-(void)changeListButtonClick{
    _isList = !_isList;
    if (_isList) {
        [self.myCollectionView setCollectionViewLayout:self.listLayout animated:YES];
    }else{
        [self.myCollectionView setCollectionViewLayout:self.gridLayout animated:YES];
    }
    //[self.myCollectionView reloadData];
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFIC_N_NAME object:@(_isList)];
}

UICollectionViewCell.m

基本布局代碼這里就不貼上來了,需要的請(qǐng)?jiān)谖恼伦詈笞孕邢螺dDemo查看抓谴。
暮蹂!注意:因?yàn)檫@里使用的是UIView動(dòng)畫,因?yàn)閁IView動(dòng)畫并不會(huì)根據(jù)我們?nèi)庋鬯吹降膭?dòng)畫效果過程中來動(dòng)態(tài)改變寬高齐邦,在動(dòng)畫開始時(shí)其寬高就已經(jīng)是結(jié)束狀態(tài)時(shí)的寬高椎侠。所以用Masonry給子視圖布局時(shí),約束對(duì)象盡可能的避免Cell的右邊和底邊措拇。否則動(dòng)畫將會(huì)出現(xiàn)異常我纪,如下圖的TitleLabel,我們能看到在切換時(shí)title寬度是直接變短的丐吓,也造成其它Label以它為約束對(duì)象時(shí)動(dòng)畫異常(下面紅色字體的Label浅悉,切換時(shí)會(huì)往下移位)。

title約束為右邊時(shí)動(dòng)畫慢放.gif

一券犁、重寫layoutSubviews

通過重寫layoutSubviews方法术健,將[super layoutSubviews]寫進(jìn)UIView動(dòng)畫中,使Cell的切換過渡動(dòng)畫更平滑粘衬。

-(void)layoutSubviews{
    [UIView animateWithDuration:0.3 animations:^{
        [super layoutSubviews];
    }];
}
二荞估、重寫setNotificationName

重寫setNotificationName方法并注冊(cè)觀察者。實(shí)現(xiàn)通知方法稚新,將通知傳來的值賦值給isList勘伺。
最后記得移除觀察者!

-(void)setNotificationName:(NSString *)notificationName{
    if ([_notificationName isEqualToString:notificationName]) return;
    _notificationName = notificationName;
    //注冊(cè)通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(isListChange:) name:_notificationName object:nil];
}

-(void)isListChange:(NSNotification *)noti{
    BOOL isList = [[noti object] boolValue];
    [self setIsList:isList];
}

-(void)dealloc{
    //移除觀察者
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
三褂删、重寫setIsList

重寫setIsList方法飞醉,通過判斷isList值改變子視圖的布局。
代碼較多屯阀,詳細(xì)代碼請(qǐng)下載Demo查看缅帘。

  • 此方法內(nèi) 接收到通知進(jìn)入時(shí)cell的frame并不準(zhǔn)確轴术,此時(shí)如果需要用到self.width,則需要自行計(jì)算钦无,例如:
-(void)setIsList:(BOOL)isList{
    if (_isList == isList) return;
    _isList = isList;
    CGFloat width = _isList ? SCREEN_WIDTH : (SCREEN_WIDTH - 5) * 0.5;
    if (_isList) {
       //......
    }else{
       //......
    }
    //......
  • 如使用Masonry
    當(dāng)布局相對(duì)簡(jiǎn)單時(shí)逗栽,約束使用mas_updateConstraints進(jìn)行更新即可。當(dāng)布局比較復(fù)雜铃诬,約束涉及到某控件寬祭陷,而這控件寬又是不固定的時(shí)候,可以考慮使用mas_remakeConstraints重做約束趣席。

  • 約束都設(shè)置完成后兵志,最后調(diào)用UIView動(dòng)畫更新約束。如果有用frame設(shè)置的宣肚,也將設(shè)置frame代碼寫在UIView動(dòng)畫內(nèi)想罕。
    !注意:如有用masonry約束關(guān)聯(lián)了 用frame設(shè)置的視圖霉涨,則此處需要把frame設(shè)置的視圖寫在前面按价。

-(void)setIsList:(BOOL)isList{
    //......
    [UIView animateWithDuration:0.3f animations:^{
        self.label3.frame = frame3;
        self.label4.frame = frame4;
        
        [self.contentView layoutIfNeeded];
    }];
}

Demo:

HYChangeableCollection

-END-
如果此文章對(duì)你有幫助,希望給個(gè)??笙瑟。有什么問題歡迎在評(píng)論區(qū)探討楼镐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市往枷,隨后出現(xiàn)的幾起案子框产,更是在濱河造成了極大的恐慌,老刑警劉巖错洁,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秉宿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡屯碴,警方通過查閱死者的電腦和手機(jī)描睦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來导而,“玉大人忱叭,你說我怎么就攤上這事〗褚眨” “怎么了窑多?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)洼滚。 經(jīng)常有香客問我,道長(zhǎng)技潘,這世上最難降的妖魔是什么遥巴? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任千康,我火速辦了婚禮,結(jié)果婚禮上铲掐,老公的妹妹穿的比我還像新娘拾弃。我一直安慰自己,他們只是感情好摆霉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布豪椿。 她就那樣靜靜地躺著,像睡著了一般携栋。 火紅的嫁衣襯著肌膚如雪搭盾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天婉支,我揣著相機(jī)與錄音鸯隅,去河邊找鬼。 笑死向挖,一個(gè)胖子當(dāng)著我的面吹牛蝌以,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播何之,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼跟畅,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了溶推?” 一聲冷哼從身側(cè)響起徊件,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎悼潭,沒想到半個(gè)月后庇忌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舰褪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年皆疹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片占拍。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡略就,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出晃酒,到底是詐尸還是另有隱情表牢,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布贝次,位于F島的核電站崔兴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜敲茄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一位谋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧堰燎,春花似錦掏父、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至仅讽,卻和暖如春陶缺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背何什。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工组哩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人处渣。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓伶贰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親罐栈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子黍衙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,100評(píng)論 1 32
  • 重點(diǎn)參考鏈接: View Programming Guide for iOS https://developer....
    Kevin_Junbaozi閱讀 4,432評(píng)論 0 15
  • 陽光傾窗破寒涼 拂塵焚香凈纖玉 風(fēng)暖勾勒光影錯(cuò) 杯盞淺嘗齒醇香 ——【午后時(shí)光?茶】明月2018.1.30
    明月姐閱讀 316評(píng)論 0 0
  • 國外的月亮似乎就是更圓琅翻,至少對(duì)于目前的中國設(shè)計(jì)師來說。這不是崇洋媚外柑贞,我們必須認(rèn)清我們中國目前的設(shè)計(jì)現(xiàn)狀方椎,與世界才...
    茂趣創(chuàng)意閱讀 1,235評(píng)論 0 10
  • 三個(gè)大坑 1、莫名奇妙的湊熱鬧:并沒有這種情況钧嘶。 2棠众、火急火燎的隨大流:并沒有這種情況。 3有决、操碎了別人的心肝:并...
    用戶高盧總督閱讀 163評(píng)論 0 0