在APP中列表是一种比较常见的数据展示方式,当有数据时,就显示数据;如果没有数据,一般不会显示一个空白页面,而是在空白页面上加一些提示信息,比如像下面这样
不同的APP会有不同的设计,但不管是什么样的设计,它在整个APP内部应该是一致的,要变也只是文字或图片稍有不同。
##现状
因为我们目前的项目还算比较庞大,所以这种列表无数据的情况出现了20多次,所以类似下面的代码出现了就有20多次。为什么说类似,因为是由不同的人写的,逻辑也是差不多,但真的各不相同,有的封装成一个方法,比如:setNoMessageView,有的直接写在viewDidLoad里面……1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18- (void)setNoMessageView
{
self.noInfoView = [[UIView alloc] initWithFrame:CGRectMake(0, 45, SCREEN_WIDTH, SCREEN_HEIGHT)];
self.noInfoView.backgroundColor = [UIColor clearColor];
[self.view addSubview:self.noInfoView];
UIImageView *carImageView = [[UIImageView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH-120)/2, 60, 120, 86)];
[carImageView setImage:[UIImage imageNamed:@"no_message.png"]];
[self.noInfoView addSubview:carImageView];
UILabel *noInfoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, SCREEN_WIDTH, 20)];
noInfoLabel.textAlignment = NSTextAlignmentCenter;
noInfoLabel.textColor = LCRGBColor(211, 211, 211);
noInfoLabel.text = NSLocalizedString(@"Dear, no information", nil);
noInfoLabel.backgroundColor = [UIColor clearColor];
noInfoLabel.font = [LCFont systemFontOfSize:20];
[self.noInfoView addSubview:noInfoLabel];
}
先不考虑重复的问题,只是孤立的看上述代码,它也有一些问题:
- self.noInfoView的frame应该视根据上下文获得的,而不是和屏幕大小绑定,而且yOffset是45也是不对的。
- carImageView的frame是固定大小的,而图片有可能变。
第一个解决办法
因为创建noInfoView的代码基本差不多,我们可以封装出一个Util方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19+ (UIView*)createNoMessageViewWithFrame:(CGRect)frame image:(UIImage*)image text:(NSString*)text
{
UIView* noMessageView = [[UIView alloc] initWithFrame:frame];
noMessageView.backgroundColor = [UIColor clearColor];
UIImageView *carImageView = [[UIImageView alloc] initWithFrame:CGRectMake((frame.size.width-image.size.width)/2, 60, image.size.width, image.size.height)];
[carImageView setImage:image];
[noMessageView addSubview:carImageView];
UILabel *noInfoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, frame.size.width, 20)];
noInfoLabel.textAlignment = NSTextAlignmentCenter;
noInfoLabel.textColor = LCRGBColor(211, 211, 211);
noInfoLabel.text = text;
noInfoLabel.backgroundColor = [UIColor clearColor];
noInfoLabel.font = [LCFont systemFontOfSize:20];
[noMessageView addSubview:noInfoLabel];
return noMessageView;
}
调用:1
2
3
4
5
6
7
8- (void)setNoMessageView
{
CGRect rect = self.shopListView.frame;
UIImage* image = [UIImage imageNamed:@"no_message.png"];
NSString* text = NSLocalizedString(@"Dear, no information", nil);
self.noInfoView = [HJUIUtil createNoMessageViewWithFrame:rect image:image text:text];
[self.view addSubview:self.noInfoView];
}
这样改看起来好多了,把共性封装,把差异作为接口留出。然后其他地方原本要写20行代码,现在只要写5行,而且多个地方调用的代码不会有太大的出入,便于阅读和理解。
第二个解决办法
上面的办法已经不错了,不过除了写5行代码之外,还给ViewController增加了一个属性:noInfoView。现在仔细想一下noInfoView出现的原因,是因为TableView没有内容显示的时候,noInfoView才显示出来,否则就隐藏。可见,这个noInfoView和TableView是紧密联系的,我们可以从UITableView的状态得出noInfoView的状态。那为什么不把它绑定到UITableView上呢?好,那就给UITableView增加一个属性,叫做emptyView。
给一个系统的类增加属性不是那么的简单,但是只要看过SVPullToRefresh的代码,就知道怎么做了。
首先,给UITableView增加一个Category。1
2
3
4
5
6
7@interface UITableView(EmptyView)
@property (nonatomic, strong, readonly) UIView *emptyView;
-(void)addEmptyViewWithImageName:(NSString*)imageName title:(NSString*)title;
@end
1 | static char UITableViewEmptyView; |
然后外部调用就很简单了,没有额外的属性,而且一句话就搞定。1
[self.shopListView.shopListTableView addEmptyViewWithImageName:@"no_message.png" title:@"Dear, no information"];