UITableView/UICollectionView中默認(rèn)占位圖的反浩克裝甲

a8.jpg.gif

相信大家都有遇到在項目中遇到過關(guān)于 UITableViewUICollectionView 實現(xiàn)下的占位圖需求芍躏。
比如某魚 App 中對于各種不同場景需求顯示的占位圖:

  • 數(shù)據(jù)加載中的占位圖
7AC3195F4F6F14D68B0FC387502952D3.png
  • 網(wǎng)絡(luò)異常時的占位圖
ED5CB7BD800A944721C6F466A2210356.png
  • 無數(shù)據(jù)時的占位圖
D2BC07B0AAD7A83B0FAFEC1FE386E31F.png

思考#


那么疑問來了,遇到這種需求時你會如何進(jìn)行相關(guān)實現(xiàn)呢?

  • 創(chuàng)建三種不同的占位圖腰涧,然后再根據(jù)不同的場景調(diào)整與之相關(guān)的**UITableVIew ** 視圖層級來進(jìn)行顯示槽唾?(當(dāng)然這里還不包括在不同場景下交互邏輯姐叁,占位圖是否可點擊操作航背?占位圖顯示時 UITableView 滾動限制等等)

  • 可能也有稍微靈活一些的方案,依舊創(chuàng)建三種不同的占位圖巫击,但是在管理視圖顯示邏輯時根據(jù)不同場景情況下將與 UITableView 大小相等的占位圖加載至或替換原有的 **UITableVIewHeaderView/TableViewFooterView ** 來進(jìn)行實現(xiàn)榆芦,這樣實現(xiàn)的好處避免了多種占位圖以及多種場景下的層級顯示處理邏輯,同時也能很好的適配各種不同 UITableView 的大小并且在相關(guān)滾動限制上能很好的進(jìn)行掌控喘鸟。

  • ......

小編以前有幸看到了某一家公司關(guān)于這方面的需求實現(xiàn)匆绣,在看了一部分源碼之后我差點就當(dāng)場原地自爆,除了復(fù)雜的多場景占位圖 Frame 變更之外還有與之附帶的多頁面代碼入侵什黑,不得不佩服當(dāng)時寫下這些代碼的人的腦力與體力崎淳,但是秉承偷懶才是 IT 行業(yè)的第一生產(chǎn)力的名言,所以小編在參考了其它一些大牛的實現(xiàn)思路后愕把,決定擼一個屬于自己的小框架拣凹。

![OJ11D}6~K(J`7]0)PSC]7JC.gif](http://upload-images.jianshu.io/upload_images/3831145-c5b34482f3bb68a4.gif?imageMogr2/auto-orient/strip)

使用方式及相關(guān)介紹#


該框架提供了三種不同場景下的占位圖顯示功能(UICollectionView 版本請參考以下 UITableVIew 實現(xiàn)流程)

1. 請先在你所使用的 UITableView 或者 UITableViewConroller 內(nèi)部實現(xiàn) WCQTableViewPlaceholderDelegate 代理方法

返回加載時的默認(rèn)占位圖方法(@required)

- (UIView *)wcq_tableViewPlaceholderInLoadingState;

返回網(wǎng)絡(luò)異常時的默認(rèn)占位圖方法(@required)

- (UIView *)wcq_tableViewPlaceholderInAnormalNetState;

返回空數(shù)據(jù)時的默認(rèn)占位圖方法(@required)

- (UIView *)wcq_tableViewPlaceholderInEmptyDatasourceState;

控制默認(rèn)占位圖顯示時 UITableView 的滾動限制(@optional)

- (BOOL)wcq_enableScroll;

2. 框架內(nèi)部實現(xiàn)了關(guān)于 UITableView 的一個分類(WCQTableViewPlaceholder),該分類為 UITableView 提供了:

  • 網(wǎng)絡(luò)異常時自動加載相關(guān)默認(rèn)占位圖的功能
- (void)wcq_setAnormalNetwork;
  • 數(shù)據(jù)加載時自動加載相關(guān)默認(rèn)占位圖的功能
- (void)wcq_setLoadingState;
  • 而空數(shù)據(jù)時自動加載相關(guān)默認(rèn)占位圖的實現(xiàn)則是基于 UITableView 數(shù)據(jù)源驅(qū)動實現(xiàn)的,使用者在使用系統(tǒng) ReloadData 方法時框架會自行判斷加載恨豁,無需使用者添加相關(guān)代碼

代碼示例#


@interface ViewController ()<UITableViewDelegate, UITableViewDataSource, WCQTableViewPlaceholderDelegate>

@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSMutableArray *dataArray;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    [self.view addSubview:self.tableView];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Refresh Methods
- (void)reloadData {
    
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    
    NSURL *URL = [NSURL URLWithString:@"http://baike.baidu.com/api/openapi/BaikeLemmaCardApi?scope=103&format=json&appid=379020&bk_key=hello&bk_length=600"];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    
    [self.tableView wcq_setLoadingState];
    NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
        if (error) {
            NSLog(@"Error: %@", error);
            [self.tableView.mj_header endRefreshing];
            [self.tableView wcq_setAnormalNetwork];
        } else {
            NSLog(@"%@ %@", response, responseObject);
            [self.tableView.mj_header endRefreshing];
            self.dataArray = [NSMutableArray arrayWithArray:@[@"1", @"2", @"3"]];
            [self.tableView reloadData];
        }
    }];
    [dataTask resume];
}

- (void)loadData {
    
    [self.tableView wcq_setLoadingState];
    [self.dataArray removeAllObjects];
    [self.tableView performSelector:@selector(reloadData) withObject:nil afterDelay:3.0];
    [self.tableView.mj_footer endRefreshing];
}

#pragma mark - UITableViewDataSource Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    return self.dataArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([UITableViewCell class])];
    cell.backgroundColor = [UIColor colorWithRed:arc4random()%256/255.0
                                           green:arc4random()%256/255.0
                                            blue:arc4random()%256/255.0
                                           alpha:1];
    return cell;
}

#pragma mark - UITableViewDelegate Methods
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    return 100;
}

#pragma mark - WCQTableViewPlaceholderDelegate Methods
- (UIView *)wcq_tableViewPlaceholderInLoadingState {
    
    UIImageView *placeholderView = [UIImageView new];
    placeholderView.contentMode = UIViewContentModeScaleAspectFill;
    placeholderView.image = [UIImage imageNamed:@"loading"];
    return placeholderView;
}

- (UIView *)wcq_tableViewPlaceholderInAnormalNetState {
    
    UIImageView *placeholderView = [UIImageView new];
    placeholderView.contentMode = UIViewContentModeScaleAspectFill;
    placeholderView.image = [UIImage imageNamed:@"anormal"];
    return placeholderView;
}

- (UIView *)wcq_tableViewPlaceholderInEmptyDatasourceState {
    
    UIImageView *placeholderView = [UIImageView new];
    placeholderView.contentMode = UIViewContentModeScaleAspectFill;
    placeholderView.image = [UIImage imageNamed:@"emptyData"];
    return placeholderView;
}

- (BOOL)wcq_enableScroll {
    
    return YES;
}

#pragma mark - Getter Methods
- (UITableView *)tableView {
    
    if (!_tableView) {
        
        _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
        _tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(reloadData)];
        _tableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadData)];
        _tableView.dataSource = self;
        _tableView.delegate = self;
        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:NSStringFromClass([UITableViewCell class])];
    }
    return _tableView;
}

- (NSMutableArray *)dataArray {
    
    if (!_dataArray) {
        
        _dataArray = [[NSMutableArray alloc] init];
    }
    return _dataArray;
}
@end


效果圖:#


WCQTableViewPlaceholder.gif

注意####

  • 下啦刷新是真正進(jìn)行網(wǎng)絡(luò)請求操作嚣镜,而上啦刷新則是模擬網(wǎng)絡(luò)請求失敗,并未進(jìn)行網(wǎng)絡(luò)請求操作橘蜜,請同學(xué)們注意

  • Demo 中所有占位圖均為圖片菊匿,如網(wǎng)絡(luò)異常占位圖付呕,圖中按鈕無法進(jìn)行相關(guān)點擊操作,如果有這方面交互需求的同學(xué)跌捆,可以在相對應(yīng)的返回默認(rèn)占位圖代理方法中實現(xiàn)徽职。

總結(jié)#


  • 對原有代碼侵入性小,建議大家可以自定義一個統(tǒng)一的 UITableView 或者 UITableViewController 進(jìn)行相關(guān)管理
  • 簡單易用同時降低開發(fā)者對于后期維護(hù)的成本佩厚,而且開放多種不同場景的默認(rèn)占位圖顯示接口

WCQTableViewPlaceholder地址(內(nèi)附Demo)

廣告#


本人也是新手入門如果發(fā)現(xiàn)本文有什么錯誤的地方可以下方留言跟我反饋姆钉,哪怕是文章的排版問題還是其他影響到閱讀體驗的問題都可以反饋我,大家一起探討如果我確實寫的有問題我會欣然接受并改正抄瓦。同時我的新浪微博是 KeepMoveingOn潮瓶,有任何問題也都可以@我,我會盡快回復(fù)大家的钙姊,感謝各位看官花費寶貴的時間閱讀此文??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毯辅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子摸恍,更是在濱河造成了極大的恐慌悉罕,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件立镶,死亡現(xiàn)場離奇詭異壁袄,居然都是意外死亡,警方通過查閱死者的電腦和手機媚媒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門嗜逻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缭召,你說我怎么就攤上這事栈顷。” “怎么了嵌巷?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵萄凤,是天一觀的道長。 經(jīng)常有香客問我搪哪,道長靡努,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任晓折,我火速辦了婚禮惑朦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘漓概。我一直安慰自己漾月,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布胃珍。 她就那樣靜靜地躺著梁肿,像睡著了一般蜓陌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上栈雳,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天护奈,我揣著相機與錄音缔莲,去河邊找鬼哥纫。 笑死,一個胖子當(dāng)著我的面吹牛痴奏,可吹牛的內(nèi)容都是我干的蛀骇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼读拆,長吁一口氣:“原來是場噩夢啊……” “哼擅憔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起檐晕,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤暑诸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后辟灰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體个榕,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年芥喇,在試婚紗的時候發(fā)現(xiàn)自己被綠了西采。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡继控,死狀恐怖械馆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情武通,我是刑警寧澤霹崎,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站冶忱,受9級特大地震影響尾菇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜朗和,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一错沽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧眶拉,春花似錦千埃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谒臼。三九已至,卻和暖如春耀里,著一層夾襖步出監(jiān)牢的瞬間蜈缤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工冯挎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留底哥,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓房官,卻偏偏與公主長得像趾徽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子翰守,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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