- GitHub: DZNEmptyDataSet
- star: 11k
注:以下內(nèi)容來(lái)源于官方源碼、 README 文檔、Demo 應(yīng)用以及個(gè)人使用總結(jié) !
DZNEmptyDataSet
DZNEmptyDataSet 是基于 UITableView/UICollectionView
的擴(kuò)展(category)類(lèi),用于在空白頁(yè)面顯示提示信息。
這是 iOS 內(nèi)建的標(biāo)準(zhǔn),用于處理空白列表和空白集合視圖。默認(rèn)情況下,如果你的列表視圖是空白的,屏幕上什么也不會(huì)顯示,它給用戶(hù)的體驗(yàn)不是很好。
集成 DZNEmptyDataSet 之后,你只需要實(shí)現(xiàn)相關(guān)協(xié)議,就可以很好地處理空白視圖,合理美觀(guān)地顯示出提示信息。
其他效果圖參考
使用該框架的項(xiàng)目
將你的項(xiàng)目添加到列表中 并且提供一張(320px)的效果圖。
空數(shù)據(jù)設(shè)計(jì)模式(The Empty Data Set Pattern)
空數(shù)據(jù)設(shè)計(jì)模式(The Empty Data Set Pattern)也被稱(chēng)為 Empty state 或者 Blank Slate。
大多數(shù)應(yīng)用程序會(huì)顯示列表視圖(UITableView
)、集合視圖(UICollectionView
),但有些時(shí)候這些頁(yè)面可能是空白的,特別是對(duì)于那些剛創(chuàng)建空賬戶(hù)的新用戶(hù)來(lái)說(shuō)。 空白界面會(huì)對(duì)用戶(hù)造成不知道如何進(jìn)行下一步操作的困惑,因?yàn)橛脩?hù)不知道屏幕空白的原因是錯(cuò)誤、Bug、網(wǎng)絡(luò)異常,還是用戶(hù)應(yīng)該自己新建內(nèi)容以恢復(fù)APP的正常狀態(tài)。
請(qǐng)閱讀這篇非常有趣的文章 Designing For The Empty States。
在 iOS 9人機(jī)界面指南 1.4.2 中也提及過(guò)類(lèi)似的指引:
如果應(yīng)用中所有的功能當(dāng)前都不可用,那么應(yīng)該顯示一些內(nèi)容來(lái)解釋當(dāng)前的情形,并建議用戶(hù)如何進(jìn)行后續(xù)操作。這部分內(nèi)容給予了用戶(hù)以反饋,使用戶(hù)相信你的應(yīng)用現(xiàn)在沒(méi)問(wèn)題。同時(shí)這也可以穩(wěn)定用戶(hù)情緒,讓他們決定是否要采取糾正措施,繼續(xù)使用應(yīng)用,還是切換到另一個(gè)應(yīng)用。
Empty Data Sets 有助于:
- 避免使用空白屏幕,并向用戶(hù)傳達(dá)屏幕空白的原因。
- 用戶(hù)指引(特別是作為引導(dǎo)頁(yè)面)。
- 避免其他中斷機(jī)制,如顯示錯(cuò)誤警報(bào)。
- 一致性和改善用戶(hù)體驗(yàn)。
- 傳遞品牌價(jià)值。
特性
- 兼容 UITableView 和 UICollectionView 。 也兼容 UISearchDisplayController 和 UIScrollView 。
- 通過(guò)顯示圖片、標(biāo)題、詳細(xì)文本、按鈕,提供布局外觀(guān)的多種可能性。
- 使用 NSAttributedString 類(lèi)提供更容易定制的外觀(guān)。
- 使用 Auto Layout 以自動(dòng)將內(nèi)容集中到表格視圖,并支持自動(dòng)旋轉(zhuǎn)。 也接受自定義垂直和水平對(duì)齊。
- 自定義背景顏色。
- 允許在整個(gè)表格矩形上輕敲手勢(shì)(有助于放棄第一個(gè)響應(yīng)者或類(lèi)似操作)。
- 提供更高級(jí)的定制,允許自定義視圖。
- 兼容 Storyboard。
- 兼容iOS 6,tvOS 9或更高版本。
- 兼容iPhone,iPad和Apple TV。
- 支持 App Store 。
這個(gè)庫(kù)已經(jīng)被設(shè)計(jì)為不需要通過(guò)擴(kuò)展(extend) UITableView 或 UICollectionView 類(lèi)的方式來(lái)實(shí)現(xiàn)了。 使用 UITableViewController 或 UICollectionViewController 類(lèi)仍然可以奏效。 只要通過(guò)遵循 DZNEmptyDataSetSource
和 DZNEmptyDataSetDelegate
協(xié)議,您將能夠完全自定義應(yīng)用程序的空狀態(tài)的內(nèi)容和外觀(guān)。
安裝
支持 CocoaPods 導(dǎo)入
pod 'DZNEmptyDataSet'
使用
完整文檔參考:CocoaPods 自動(dòng)生成文檔
導(dǎo)入
手動(dòng)導(dǎo)入:
#import "UIScrollView+EmptyDataSet.h"
作為框架導(dǎo)入:
#import <DZNEmptyDataSet/UIScrollView+EmptyDataSet.h>
遵循協(xié)議
在需要顯示空白數(shù)據(jù)集的視圖控制器中,聲明該視圖控制器遵守DZNEmptyDataSetSource
、DZNEmptyDataSetDelegate
協(xié)議:
// 遵守 DZNEmptyDataSetSource 、DZNEmptyDataSetDelegate 協(xié)議
@interface MainViewController : UITableViewController <DZNEmptyDataSetSource, DZNEmptyDataSetDelegate>
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.emptyDataSetSource = self;
self.tableView.emptyDataSetDelegate = self;
}
實(shí)現(xiàn)數(shù)據(jù)源協(xié)議 DZNEmptyDataSetSource
實(shí)現(xiàn)該協(xié)議可以設(shè)置你想要在空白頁(yè)面顯示的內(nèi)容,并且充分利用 NSAttributedString
類(lèi)來(lái)自定義文本樣式。
空白頁(yè)顯示圖片
// MARK: 空白頁(yè)顯示圖片
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
return [UIImage imageNamed:@"lion"];
}
實(shí)現(xiàn) <DZNEmptyDataSetSource>
協(xié)議的 imageForEmptyDataSet:
方法,返回一張圖片即可。
頁(yè)面顯示效果如下圖所示:
空白頁(yè)顯示圖片和標(biāo)題
繼續(xù)上一個(gè)示例,在圖片下方添加標(biāo)題文字:
// MARK: 空白頁(yè)顯示圖片
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
return [UIImage imageNamed:@"lion"];
}
// MARK: 空白頁(yè)顯示標(biāo)題
- (NSAttributedString *)titleForEmptyDataSet:(UIScrollView *)scrollView {
NSString *title = @"獅子王";
NSDictionary *attributes = @{
NSFontAttributeName:[UIFont boldSystemFontOfSize:18.0f],
NSForegroundColorAttributeName:[UIColor darkGrayColor]
};
return [[NSAttributedString alloc] initWithString:title attributes:attributes];
}
頁(yè)面顯示效果如下圖所示:
空白頁(yè)顯示圖片、標(biāo)題、詳細(xì)描述
這一次,除了在空白頁(yè)面顯示一張圖片和標(biāo)題,我們還可以在下方添加更詳細(xì)的描述文字:
// MARK: 空白頁(yè)顯示圖片
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
return [UIImage imageNamed:@"lion"];
}
// MARK: 空白頁(yè)顯示標(biāo)題
- (NSAttributedString *)titleForEmptyDataSet:(UIScrollView *)scrollView {
NSString *title = @"獅子王";
NSDictionary *attributes = @{
NSFontAttributeName:[UIFont boldSystemFontOfSize:18.0f],
NSForegroundColorAttributeName:[UIColor darkGrayColor]
};
return [[NSAttributedString alloc] initWithString:title attributes:attributes];
}
// MARK: 空白頁(yè)顯示詳細(xì)描述
- (NSAttributedString *)descriptionForEmptyDataSet:(UIScrollView *)scrollView {
NSString *text = @"我只在必要時(shí)才勇敢,勇敢并不意味著要到處闖禍!";
NSMutableParagraphStyle *paragraph = [NSMutableParagraphStyle new];
paragraph.lineBreakMode = NSLineBreakByWordWrapping;
paragraph.alignment = NSTextAlignmentCenter;
NSDictionary *attributes = @{
NSFontAttributeName:[UIFont systemFontOfSize:14.0f],
NSForegroundColorAttributeName:[UIColor lightGrayColor],
NSParagraphStyleAttributeName:paragraph
};
return [[NSAttributedString alloc] initWithString:text attributes:attributes];
}
頁(yè)面顯示效果如下圖所示:
設(shè)置內(nèi)容的垂直偏移量
你還可以調(diào)整內(nèi)容視圖的垂直對(duì)齊(垂直偏移量)方式:
// 向上偏移量為表頭視圖高度/2
- (CGFloat)verticalOffsetForEmptyDataSet:(UIScrollView *)scrollView {
return -self.tableView.tableHeaderView.frame.size.height/2.0f;
}
或者返回一個(gè)固定值:
- (CGFloat)verticalOffsetForEmptyDataSet:(UIScrollView *)scrollView {
return -64;
}
頁(yè)面效果如下所示:
設(shè)置內(nèi)容元素之間的垂直間距
你也可以設(shè)置所有組件彼此之間的上下間距(默認(rèn)間距為11 pt):
- (CGFloat)spaceHeightForEmptyDataSet:(UIScrollView *)scrollView {
return 50.0f;
}
純粹為了測(cè)試,我把這個(gè)垂直間距的值設(shè)置的很大,頁(yè)面效果如下所示:
空白頁(yè)添加按鈕
除了在空白頁(yè)添加靜態(tài)的圖片和文本,我們還可以在空白頁(yè)添加可交互的按鈕。設(shè)置空白頁(yè)按鈕的文字:
#pragma mark - <DZNEmptyDataSetSource>
// MARK: 空白頁(yè)顯示圖片
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
return [UIImage imageNamed:@"unlogin"];
}
// MARK: 空白頁(yè)顯示標(biāo)題
- (NSAttributedString *)titleForEmptyDataSet:(UIScrollView *)scrollView {
NSString *title = @"您當(dāng)前未登錄";
NSDictionary *attributes = @{
NSFontAttributeName:[UIFont boldSystemFontOfSize:14.0f],
NSForegroundColorAttributeName:[UIColor lightGrayColor]
};
return [[NSAttributedString alloc] initWithString:title attributes:attributes];
}
// MARK: 空白頁(yè)添加按鈕,設(shè)置按鈕文字
- (NSAttributedString *)buttonTitleForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state {
// 設(shè)置按鈕標(biāo)題
NSString *buttonTitle = @"點(diǎn)擊登錄";
NSDictionary *attributes = @{
NSFontAttributeName:[UIFont boldSystemFontOfSize:17.0f],
NSForegroundColorAttributeName: [UIColor flatSkyBlueColor]
};
return [[NSAttributedString alloc] initWithString:buttonTitle attributes:attributes];
}
#pragma mark - <DZNEmptyDataSetDelegate>
- (void)emptyDataSet:(UIScrollView *)scrollView didTapButton:(UIButton *)button {
// 處理空白頁(yè)面按鈕點(diǎn)擊事件
NSLog(@"處理空白頁(yè)面按鈕點(diǎn)擊事件");
}
正如以上示例代碼所示,
實(shí)現(xiàn) <DZNEmptyDataSetSource>
協(xié)議的 buttonTitleForEmptyDataSet:forState:
方法,并返回一個(gè) NSAttributedString
實(shí)例來(lái)設(shè)置按鈕標(biāo)題。
實(shí)現(xiàn) <DZNEmptyDataSetDelegate>
協(xié)議的 emptyDataSet:didTapButton:
方法,可以處理該按鈕的點(diǎn)擊響應(yīng)事件。
頁(yè)面效果如下所示:
注意到,設(shè)置按鈕標(biāo)題的 buttonTitleForEmptyDataSet:forState:
方法中,還返回了 UIControlState
屬性,因此我們還可以設(shè)置按鈕高亮或者默認(rèn)狀態(tài)下的顏色,示例代碼如下:
- (NSAttributedString *)buttonTitleForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state {
// 設(shè)置按鈕標(biāo)題
NSString *buttonTitle = @"按鈕標(biāo)題";
UIColor *buttonColor = [UIColor colorWithHexString:(state == UIControlStateNormal) ? @"007ee5" : @"48a1ea"];
NSDictionary *attributes = @{
NSFontAttributeName:[UIFont systemFontOfSize:15.0],
NSForegroundColorAttributeName: buttonColor
};
return [[NSAttributedString alloc] initWithString:buttonTitle attributes:attributes];
}
說(shuō)明:
-
colorWithHexString:
表示通過(guò)十六進(jìn)制值設(shè)置顏色,該方法來(lái)自 Chameleon 顏色框架。 -
statement ? True : False
是一個(gè)三元表達(dá)式,判斷值為真,則執(zhí)行 True,否則執(zhí)行 False。
空白頁(yè)添加按鈕,個(gè)性化按鈕標(biāo)題
空白頁(yè)面中僅添加一張圖片和一個(gè)按鈕標(biāo)題,把按鈕標(biāo)題中 「點(diǎn)擊重試」四個(gè)字顏色高亮加粗:
#pragma mark - <DZNEmptyDataSetSource>
// MARK: 空白頁(yè)顯示圖片
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
return [UIImage imageNamed:@"placeholder_no_network"];
}
// MARK: 空白頁(yè)添加按鈕,設(shè)置按鈕文字
- (NSAttributedString *)buttonTitleForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state {
// 設(shè)置按鈕標(biāo)題
NSString *buttonTitle = @"網(wǎng)絡(luò)不給力,請(qǐng)點(diǎn)擊重試哦~";
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:buttonTitle];
// 設(shè)置所有字體大小為 #15
[attributedString addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:15.0]
range:NSMakeRange(0, buttonTitle.length)];
// 設(shè)置所有字體顏色為淺灰色
[attributedString addAttribute:NSForegroundColorAttributeName
value:[UIColor lightGrayColor]
range:NSMakeRange(0, buttonTitle.length)];
// 設(shè)置指定4個(gè)字體為藍(lán)色
[attributedString addAttribute:NSForegroundColorAttributeName
value:HexColor(@"#007EE5")
range:NSMakeRange(7, 4)];
return attributedString;
}
// MARK: 空白頁(yè)背景顏色
- (nullable UIColor *)backgroundColorForEmptyDataSet:(UIScrollView *)scrollView {
return [UIColor colorWithHexString:@"#f0f3f5"];
}
// MARK: 設(shè)置空白頁(yè)內(nèi)容的垂直便宜量
- (CGFloat)verticalOffsetForEmptyDataSet:(UIScrollView *)scrollView {
return -70.0f;
}
#pragma mark - <DZNEmptyDataSetDelegate>
- (void)emptyDataSet:(UIScrollView *)scrollView didTapButton:(UIButton *)button {
// 處理空白頁(yè)面按鈕點(diǎn)擊事件
NSLog(@"處理空白頁(yè)面按鈕點(diǎn)擊事件");
}
- (void)emptyDataSetWillAppear:(UIScrollView *)scrollView {
self.tableView.contentOffset = CGPointZero;
}
頁(yè)面效果如下所示:
空白頁(yè)添加按鈕,設(shè)置按鈕背景圖片
通過(guò)實(shí)現(xiàn) <DZNEmptyDataSetSource>
協(xié)議的 buttonBackgroundImageForEmptyDataSet: forState:
方法,你可以設(shè)置默認(rèn)狀態(tài)(即 UIControlStateNormal
)和高亮狀態(tài)(即 UIControlStateHighlighted
)下的按鈕背景圖片。
背景圖片類(lèi)似這樣的:
示例代碼如下:
#pragma mark - <DZNEmptyDataSetSource>
// MARK: 空白頁(yè)顯示圖片
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
if (self.isLoading) {
return [UIImage imageNamed:@"loading_imgBlue_78x78"];
} else {
return [UIImage imageNamed:@"placeholder_foursquare"];
}
}
// MARK: 空白頁(yè)圖片動(dòng)畫(huà)
- (CAAnimation *)imageAnimationForEmptyDataSet:(UIScrollView *)scrollView {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
animation.toValue = [NSValue valueWithCATransform3D: CATransform3DMakeRotation(M_PI_2, 0.0, 0.0, 1.0) ];
animation.duration = 0.25;
animation.cumulative = YES;
animation.repeatCount = MAXFLOAT;
return animation;
}
// MARK: 空白頁(yè)顯示詳細(xì)描述
- (NSAttributedString *)descriptionForEmptyDataSet:(UIScrollView *)scrollView {
NSString *text = @"Nobody has liked or commented on your check-ins yet.";
NSMutableParagraphStyle *paragraph = [NSMutableParagraphStyle new];
paragraph.lineBreakMode = NSLineBreakByWordWrapping;
paragraph.alignment = NSTextAlignmentCenter;
NSDictionary *attributes = @{
NSFontAttributeName:[UIFont systemFontOfSize:14.0f],
NSForegroundColorAttributeName:[UIColor colorWithHexString:@"#cecbc6"],
NSParagraphStyleAttributeName:paragraph
};
return [[NSAttributedString alloc] initWithString:text attributes:attributes];
}
// MARK: 空白頁(yè)添加按鈕,設(shè)置按鈕文字
- (NSAttributedString *)buttonTitleForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state {
// 設(shè)置按鈕標(biāo)題
NSString *buttonTitle = @"Add friends to get started!";
UIColor *buttonColor = [UIColor colorWithHexString:(state == UIControlStateNormal) ? @"00aeef" : @"ffffff"];
NSDictionary *attributes = @{
NSFontAttributeName:[UIFont systemFontOfSize:14.0],
NSForegroundColorAttributeName: buttonColor
};
return [[NSAttributedString alloc] initWithString:buttonTitle attributes:attributes];
}
// MARK: 空白頁(yè)添加按鈕,設(shè)置按鈕背景圖片
- (UIImage *)buttonBackgroundImageForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state {
UIImage *image;
if (state == UIControlStateNormal) {
image = [UIImage imageNamed:@"button_background_foursquare_normal"];
}
if (state == UIControlStateHighlighted) {
image = [UIImage imageNamed:@"button_background_foursquare_highlight"];
}
UIEdgeInsets capInsets = UIEdgeInsetsMake(25.0, 25.0, 25.0, 25.0);
UIEdgeInsets rectInsets = UIEdgeInsetsMake(0.0, 10, 0.0, 10);
return [[image resizableImageWithCapInsets:capInsets resizingMode:UIImageResizingModeStretch] imageWithAlignmentRectInsets:rectInsets];
}
// MARK: 空白頁(yè)背景顏色
- (nullable UIColor *)backgroundColorForEmptyDataSet:(UIScrollView *)scrollView {
return [UIColor colorWithHexString:@"#fcfcfa"];
}
// MARK: 設(shè)置各個(gè)視圖元素之間的垂直間距,默認(rèn)為 11pt
- (CGFloat)spaceHeightForEmptyDataSet:(UIScrollView *)scrollView {
return 9.0;
}
#pragma mark - <DZNEmptyDataSetDelegate>
- (void)emptyDataSet:(UIScrollView *)scrollView didTapButton:(UIButton *)button {
// 處理空白頁(yè)面按鈕點(diǎn)擊事件
NSLog(@"處理空白頁(yè)面按鈕點(diǎn)擊事件");
self.loading = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.loading = NO;
});
}
- (BOOL)emptyDataSetShouldAnimateImageView:(UIScrollView *)scrollView {
return self.isLoading;
}
以上代碼設(shè)置了按鈕文字標(biāo)題,和按鈕的背景圖片。頁(yè)面效果如下所示:
設(shè)置按鈕的背景顏色
通過(guò)設(shè)置按鈕背景圖片的方法也可以設(shè)置按鈕背景顏色:
- (UIImage *)buttonBackgroundImageForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state {
UIImage *image = [UIImage imageWithColor:[UIColor greenColor]];
return image;
}
以上代碼使用了 YYKit 框架中的 imageWithColor:
方法,可以通過(guò)顏色生成純色圖片。
設(shè)置按鈕圖片
如果你的按鈕定制化需求很高,也通過(guò)實(shí)現(xiàn) buttonImageForEmptyDataSet: forState:
方法,你可以直接把按鈕設(shè)置成一張圖片:
#pragma mark - <DZNEmptyDataSetSource>
// MARK: 空白頁(yè)顯示圖片
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
return [UIImage imageNamed:@"placeholder_network_error_404"];
}
// MARK: 空白頁(yè)顯示標(biāo)題
- (NSAttributedString *)titleForEmptyDataSet:(UIScrollView *)scrollView {
NSString *title = @"您當(dāng)前未連接網(wǎng)絡(luò)";
NSDictionary *attributes = @{
NSFontAttributeName:[UIFont systemFontOfSize:15.0],
NSForegroundColorAttributeName:[UIColor colorWithHexString:@"#25282b"]
};
return [[NSAttributedString alloc] initWithString:title attributes:attributes];
}
// MARK: 空白頁(yè)添加按鈕,設(shè)置按鈕圖片
- (UIImage *)buttonImageForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state {
return [UIImage imageNamed:@"button_Image"];
}
#pragma mark - <DZNEmptyDataSetDelegate>
- (void)emptyDataSet:(UIScrollView *)scrollView didTapButton:(UIButton *)button {
// 處理空白頁(yè)面按鈕點(diǎn)擊事件
NSLog(@"處理空白頁(yè)面按鈕點(diǎn)擊事件");
}
頁(yè)面效果如下所示:
設(shè)置圖片的 tintColor
屬性
就是設(shè)置圖片顏色,腦補(bǔ)中。。。
- (UIColor *)imageTintColorForEmptyDataSet:(UIScrollView *)scrollView {
return [UIColor yellowColor];
}
設(shè)置空白頁(yè)面的背景色
通過(guò)實(shí)現(xiàn) backgroundColorForEmptyDataSet:
方法并返回 UIColor
實(shí)例就可以設(shè)置空白頁(yè)面的背景色了,這個(gè)方法,之前的示例代碼中也出現(xiàn)過(guò)。
我們?cè)谏弦粋€(gè)示例代碼中添加以下代碼來(lái)對(duì)比看看:
// MARK: 空白頁(yè)背景顏色
- (nullable UIColor *)backgroundColorForEmptyDataSet:(UIScrollView *)scrollView {
return [UIColor colorWithHexString:@"#f0f3f5"];
}
頁(yè)面效果如下所示:
設(shè)置自定義視圖
如果你需要設(shè)置更復(fù)雜的布局,也可以設(shè)置并返回自定義視圖:
- (UIView *)customViewForEmptyDataSet:(UIScrollView *)scrollView {
UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[activityView startAnimating];
return activityView;
}
以上代碼在空白頁(yè)面中顯示一個(gè)加載視圖,頁(yè)面效果如下所示:
設(shè)置圖片動(dòng)畫(huà)
為圖片添加旋轉(zhuǎn)動(dòng)畫(huà)。
#pragma mark - <DZNEmptyDataSetSource>
// MARK: 空白頁(yè)顯示圖片
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
return [UIImage imageNamed:@"lion"];
}
// MARK: 設(shè)置圖片動(dòng)畫(huà): 旋轉(zhuǎn)
- (CAAnimation *)imageAnimationForEmptyDataSet:(UIScrollView *)scrollView {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath: @"transform"];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2, 0.0, 0.0, 1.0)];
animation.duration = 0.25;
animation.cumulative = YES;
animation.repeatCount = MAXFLOAT;
return animation;
}
#pragma mark - DZNEmptyDataSetDelegate
// 向代理請(qǐng)求圖像視圖動(dòng)畫(huà)權(quán)限。 默認(rèn)值為NO。
// 確保從 imageAnimationForEmptyDataSet 返回有效的 CAAnimation 對(duì)象:
- (BOOL)emptyDataSetShouldAnimateImageView:(UIScrollView *)scrollView {
return YES;
}
頁(yè)面效果如下所示:
設(shè)置圖片動(dòng)畫(huà),縮放動(dòng)畫(huà)
#pragma mark - <DZNEmptyDataSetSource>
// MARK: 空白頁(yè)顯示圖片
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
return [UIImage imageNamed:@"placeholder_heart"];
}
// MARK: 設(shè)置圖片動(dòng)畫(huà): 縮放動(dòng)畫(huà)
- (CAAnimation *)imageAnimationForEmptyDataSet:(UIScrollView *)scrollView
{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
animation.duration = 1.25;
animation.cumulative = NO;
animation.repeatCount = MAXFLOAT;
animation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 45, 45)];
return animation;
}
#pragma mark - DZNEmptyDataSetDelegate
// 向代理請(qǐng)求圖像視圖動(dòng)畫(huà)權(quán)限。 默認(rèn)值為NO。
// 確保從 imageAnimationForEmptyDataSet 返回有效的 CAAnimation 對(duì)象:
- (BOOL)emptyDataSetShouldAnimateImageView:(UIScrollView *)scrollView {
return YES;
}
頁(yè)面效果如下所示:
我們發(fā)現(xiàn)在官方的 Applications Demo 應(yīng)用中的空白視圖中的動(dòng)畫(huà)是這樣的:
空白視圖默認(rèn)情況下顯示一張【靜態(tài)圖片】,當(dāng)用戶(hù)點(diǎn)擊【靜態(tài)圖片】以后,該圖片會(huì)被替換成【加載轉(zhuǎn)圈】。
通過(guò)閱讀源碼,可以發(fā)現(xiàn)它是這樣工作的:
- 首先在遵循協(xié)議的視圖控制器實(shí)現(xiàn)文件中聲明了一個(gè)
BOOL
類(lèi)型的變量,用來(lái)記錄空白頁(yè)面當(dāng)前的加載狀態(tài):
@property (nonatomic, assign, getter=isLoading) BOOL loading;
- 然后為該屬性設(shè)置
setter
方法,重新加載空數(shù)據(jù)集視圖:
// 設(shè)置當(dāng)前頁(yè)面的加載狀態(tài)
- (void)setLoading:(BOOL)loading {
// 如果當(dāng)前頁(yè)面的加載狀態(tài)和之前一樣,返回
if (self.isLoading == loading) {
return;
}
// 不一樣,則刷新空白頁(yè)面
_loading = loading;
[self.tableView reloadEmptyDataSet];
}
- 接下來(lái)要實(shí)現(xiàn)幾個(gè)關(guān)聯(lián)協(xié)議
#pragma mark - DZNEmptyDataSetSource
#pragma mark 設(shè)置空白頁(yè)圖片
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
if (self.isLoading) {
// 圓形加載圖片
return [UIImage imageNamed:@"loading_imgBlue_78x78"];
}else {
// 默認(rèn)靜態(tài)圖片
return [UIImage imageNamed:@"staticImage"];
}
}
#pragma mark 圖片旋轉(zhuǎn)動(dòng)畫(huà)
- (CAAnimation *)imageAnimationForEmptyDataSet:(UIScrollView *)scrollView
{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
animation.toValue = [NSValue valueWithCATransform3D: CATransform3DMakeRotation(M_PI_2, 0.0, 0.0, 1.0) ];
animation.duration = 0.25;
animation.cumulative = YES;
animation.repeatCount = MAXFLOAT;
return animation;
}
#pragma mark - DZNEmptyDataSetDelegate
#pragma mark 是否開(kāi)啟動(dòng)畫(huà)
- (BOOL)emptyDataSetShouldAnimateImageView:(UIScrollView *)scrollView {
return self.isLoading;
}
#pragma mark 空白頁(yè)面被點(diǎn)擊時(shí)刷新頁(yè)面
- (void)emptyDataSet:(UIScrollView *)scrollView didTapView:(UIView *)view {
// 空白頁(yè)面被點(diǎn)擊時(shí)開(kāi)啟動(dòng)畫(huà),reloadEmptyDataSet
self.loading = YES;
// 執(zhí)行加載任務(wù)...
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 任務(wù)加載完成后關(guān)閉動(dòng)畫(huà),reloadEmptyDataSet
self.loading = NO;
});
}
實(shí)現(xiàn)代理協(xié)議 DZNEmptyDataSetDelegate
通過(guò)實(shí)現(xiàn) DZNEmptyDataSetDelegate
協(xié)議,可以設(shè)置你期望從空白頁(yè)面返回的的行為,并接收用戶(hù)交互事件。
- 設(shè)置是否 渲染和顯示空白頁(yè)面 (默認(rèn)值為
YES
)
- (BOOL)emptyDataSetShouldDisplay:(UIScrollView *)scrollView {
return YES;
}
- 設(shè)置是否 以淡入方式顯示空白頁(yè)面 。 (默認(rèn)值為
YES
)
- (BOOL)emptyDataSetShouldFadeIn:(UIScrollView *)scrollView {
return YES;
}
- 強(qiáng)制顯示空數(shù)據(jù)集:當(dāng)項(xiàng)目數(shù)量大于0時(shí),請(qǐng)求代理是否仍應(yīng)顯示空數(shù)據(jù)集。(默認(rèn)值為NO)
- (BOOL)emptyDataSetShouldBeForcedToDisplay:(UIScrollView *)scrollView;
-
獲取交互權(quán)限:是否接收用戶(hù)點(diǎn)擊事件 (默認(rèn)值為
YES
):
- (BOOL)emptyDataSetShouldAllowTouch:(UIScrollView *)scrollView {
// 如果正在加載中,則不響應(yīng)用戶(hù)交互。
return !self.isLoading;
}
-
獲取滾動(dòng)權(quán)限(默認(rèn)值為
NO
):
- (BOOL)emptyDataSetShouldAllowScroll:(UIScrollView *)scrollView;
-
獲取圖像動(dòng)畫(huà)權(quán)限:是否開(kāi)啟圖片動(dòng)畫(huà)(默認(rèn)值為
NO
):
- (BOOL)emptyDataSetShouldAnimateImageView:(UIScrollView *)scrollView {
return YES;
}
- 空白數(shù)據(jù)集 視圖被點(diǎn)擊 時(shí)觸發(fā)該方法:
- (void)emptyDataSet:(UIScrollView *)scrollView didTapView:(UIView *)view {
// 處理視圖點(diǎn)擊事件...
}
- 空白數(shù)據(jù)集 按鈕被點(diǎn)擊時(shí) 觸發(fā)該方法:
- (void)emptyDataSet:(UIScrollView *)scrollView didTapButton:(UIButton *)button {
// 處理按鈕點(diǎn)擊事件...
}
- 空白頁(yè)將要出現(xiàn)
- (void)emptyDataSetWillAppear:(UIScrollView *)scrollView {
// 如果你的空白占位圖與需求向左,發(fā)生偏移,可如下設(shè)置:
self.tableView.contentOffset = CGPointZero;
}
- 空白頁(yè)已經(jīng)出現(xiàn)
- (void)emptyDataSetDidAppear:(UIScrollView *)scrollView;
- 空白頁(yè)將要消失
- (void)emptyDataSetWillDisappear:(UIScrollView *)scrollView;
- 空白頁(yè)已經(jīng)消失
- (void)emptyDataSetDidDisappear:(UIScrollView *)scrollView;
刷新布局
如果你需要刷新空白頁(yè)面布局,只需調(diào)用:
[self.tableView reloadData];
或者
[self.collectionView reloadData];
這取決于你用的是哪一個(gè)視圖(UITableView
/UICollectionView
)。
強(qiáng)制布局更新
你還可以調(diào)用 [self.tableView reloadEmptyDataSet]
以使當(dāng)前空白頁(yè)面布局無(wú)效,并觸發(fā)布局更新,繞過(guò) -reloadData
方法。 如果你的數(shù)據(jù)源上有很多邏輯處理,當(dāng)你不需要或者想避免調(diào)用 -reloadData
方法時(shí)這可能很有用。 當(dāng)使用 UIScrollView
滾動(dòng)視圖時(shí),[self.scrollView reloadEmptyDataSet]
是刷新內(nèi)容的唯一方法。
彩蛋
我在 GitHub 上傳了相關(guān)代碼的實(shí)現(xiàn)源碼 iOS-Samples/HQLTableViewDemo,有需要的可以去看看,當(dāng)然,你也可以直接去下載 DZNEmptyDataSet 中的 Demo,相信你能得到啟發(fā)。