需求如下:
屏幕快照 2018-09-17 下午2.41.31.png
在每个项目中,都会在请求数据为空或者网络不好的时候,提示用户当前网络状态的占位图。已达到效果和美观上都给人比较好的提示。以前都是针对不同场景展示不同的站位图片,每个用到的地方,都要自己写一遍空视图。由于该项目中用到的地方比较多,所以封装了出来。使用者,直接传入想对应页面的占位图枚举参数即可。不需要增加太多的代码。
思路:
第一种:空视图无非就是一个View 和一个用于展示文案的UILabel。
第二种:空视图还可以展示一个view+一个用于刷新试图的UIButton 按钮。
·首先我们需要封装一个无数据占位图
一个项目中,无数据占位图不光只有一种,但是可以看到他们的布局是非常相似的,所以我的做法是根据不同的值,创建不同的UI。
首先先要定一个一个枚举
typedef enum{
TimeOutEmptyType = 0, // 网络请求超时
NoneSearchDataEmptyType, // 暂无搜索结果
NoneDataEmptyType, // 暂无数据
ErrorEmptyType, // 页面出错啦~
LocationErrorEmptyType, // 无法获取位置信息
NoNetWorkEmptyType, // 网络无法连接
NoShopAssitantType, // 没有店铺助理
NoInspectionTemplateType, // 没有巡检模版
NoInspectionTaskType, // 没有巡检任务
NOOpenDoorDataType, // 没有开门数据
NoneVisitorType, // 没有拜访者数据
NORepairRecordDataType, // 没有维修记录
NOEMRecordDataType, // 没有保养记录
NoBlueToothDoor, // 没有附近的门
NoDeviceSelect, // 没有选择设备
NoNoticeType, // 没有通知记录
NoAnnounceType, // 没有公告记录
NoPaymentType, // 没有收费记录
NoTicketType // 没有工单待办记录
}EmptyType;
当然这肯定不是项目中全部的空视图,它会根据业务需求不断的增加。
.h
@interface SCEmptyView : UIView
@property (nonatomic, strong) UIImageView *emptyImage;
@property (nonatomic, strong) UILabel *titleLab;
@property (nonatomic, strong) UILabel *subTitleLab;
@property (nonatomic, strong) UIButton* retryBtn;
提供两个类方法,用于直接创建空视图。
+ (SCEmptyView*)defaultEmptyView;
+ (SCEmptyView*)emptyViewWithImage:(UIImage*)img title:(NSString*)title subTitle:(NSString*)subTitle;
初始化空界面,返回自定义空数据View
/*!
* @author wyy
*
* @brief 初始化空界面
*
* @param icon 图标
* @param title 标题
* @param subTitle 副标题
* @param btnTitle 按钮文字
*
* @return 返回自定义空数据View
*/
- (SCEmptyView*)initWithFrame:(CGRect)frame icon:(NSString*)icon title:(NSString*)title subTitle:(NSString*)subTitle buttonTitle:(NSString *)btnTitle;
根据空数据原因类型获取空界面,返回空数据View
+ (SCEmptyView*)emptyViewWithType:(EmptyType)emptyType frame:(CGRect)frame;
ok 那就来看一下具体实现吧。.m
@implementation SCEmptyView
- (UIView *)initWithIcon:(NSString *)icon Title:(NSString *)title ButtonTitle:(NSString *)btnTitle OtherTitles:(NSArray *)titles
{
if (self = [self init]) {
self.frame = CGRectMake(0, 0, kSCREEN_WIDTH, kSCREEN_HEIGHT);
self.tag = 65535;
CGFloat wh = 130;
UIImageView *imgView=[[UIImageView alloc] initWithFrame:CGRectMake(kSCREEN_WIDTH*0.5-wh*0.5, 85, wh, wh)];
if (icon != nil && ![icon isEqualToString:@""]) {
[imgView setImage:[UIImage imageNamed:icon]];
}
[self addSubview:imgView];
UILabel *textLabel=[[UILabel alloc] initWithFrame:CGRectMake(15, CGRectGetMaxY(imgView.frame) + 10, kSCREEN_WIDTH - 2*15, 18)];
textLabel.textAlignment=NSTextAlignmentCenter;
textLabel.textColor = [UIColor blackColor];
textLabel.font = [UIFont systemFontOfSize:17];
textLabel.numberOfLines = 0;
textLabel.text = title;
[textLabel sizeToFit];
textLabel.center = CGPointMake(self.center.x, textLabel.center.y);
[self addSubview:textLabel];
if (titles.count > 0) {
for (NSString *titleStr in titles) {
textLabel=[[UILabel alloc] initWithFrame:CGRectMake(15, CGRectGetMaxY(textLabel.frame)+10 , kSCREEN_WIDTH - 2*15, 15)];
textLabel.textAlignment=NSTextAlignmentCenter;
textLabel.textColor = [UIColor blackColor];
textLabel.font=[UIFont systemFontOfSize:14];
textLabel.text = titleStr;
textLabel.numberOfLines = 0;
[textLabel sizeToFit];
textLabel.center = CGPointMake(self.center.x, textLabel.center.y);
[self addSubview:textLabel];
}
}
if (btnTitle != nil && ![btnTitle isEqualToString:@""]) {
UIButton *addNewBtn = [[UIButton alloc] initWithFrame:CGRectMake(kSCREEN_WIDTH*0.5-60, CGRectGetMaxY(textLabel.frame) + 5, 120, 38)];
[addNewBtn setTitle:btnTitle forState:UIControlStateNormal];
[addNewBtn setTitleColor:[UIColor greenColor] forState:UIControlStateNormal];
addNewBtn.titleLabel.font = [UIFont systemFontOfSize:17];
[addNewBtn addTarget:self action:@selector(btnClicked) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:addNewBtn];
}
self.backgroundColor = [UIColor SCBackGroundColor];
}
return self;
}
初始化
- (id)init {
self = [super init];
if (self) {
[self initViews];
}
return self;
}
- (void)initViews {
_emptyImage = [[UIImageView alloc] init];
[self addSubview:_emptyImage];
_titleLab = [[UILabel alloc] init];
_titleLab.textAlignment = NSTextAlignmentCenter;
_titleLab.textColor = COLOR(124,121,122,1);
_titleLab.font = [UIFont systemFontOfSize:17];
[self addSubview:_titleLab];
_subTitleLab = [[UILabel alloc] init];
_subTitleLab.textAlignment = NSTextAlignmentCenter;
_subTitleLab.textColor = [UIColor greenColor];
_subTitleLab.font = [UIFont systemFontOfSize:14];
[self addSubview:_subTitleLab];
[_emptyImage mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.mas_centerX);
make.top.equalTo(self.mas_top).with.offset(85);
make.width.mas_equalTo(130);
make.height.mas_equalTo(130);
}];
[_titleLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(_emptyImage.mas_bottom).with.offset(10);
make.left.equalTo(self.mas_left).with.offset(15);
make.right.equalTo(self.mas_right).with.offset(-15);
make.height.mas_equalTo(18);
}];
[_subTitleLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(_titleLab.mas_bottom).with.offset(10);
make.left.equalTo(self.mas_left).with.offset(15);
make.right.equalTo(self.mas_right).with.offset(-15);
make.height.mas_equalTo(15);
}];
}
默认的空视图
+ (SCEmptyView*)defaultEmptyView {
if ([[SCAppInitialize shareInstance] checkNetStatus] ==AFNetworkReachabilityStatusReachableViaWiFi || [[SCAppInitialize shareInstance] checkNetStatus] ==AFNetworkReachabilityStatusReachableViaWWAN || [[SCAppInitialize shareInstance] checkNetStatus] ==AFNetworkReachabilityStatusUnknown) {
return [[SCEmptyView alloc] initWithIcon:@"ic_no_ticket" Title:@"暂无数据" ButtonTitle:nil OtherTitles:nil];
}else{
//无网络
return [[SCEmptyView alloc] initWithIcon:@"" Title:@"网络无法连接" ButtonTitle:@"重试" OtherTitles:[NSArray arrayWithObjects:@"请检查你的手机是否连联网", nil]];
}
}
+ (SCEmptyView*)emptyViewWithImage:(UIImage*)img title:(NSString*)title subTitle:(NSString*)subTitle {
SCEmptyView *emptyView = [[SCEmptyView alloc] init];
emptyView.emptyImage.image = img;
emptyView.titleLab.text = title;
emptyView.subTitleLab.text = subTitle;
return emptyView;
}
- (SCEmptyView*)initWithFrame:(CGRect)frame icon:(NSString*)icon title:(NSString*)title subTitle:(NSString*)subTitle buttonTitle:(NSString *)btnTitle;{
self = [super initWithFrame:frame];
if (self) {
//空图标
_emptyImage = [[UIImageView alloc] initWithFrame:CGRectMake((self.width-130)/2, 75, 130, 130)];
_emptyImage.image = [UIImage imageNamed:icon];
_emptyImage.contentMode = UIViewContentModeScaleAspectFit;
[self addSubview:_emptyImage];
//显示标题
_titleLab = [[UILabel alloc] initWithFrame:CGRectMake(15, _emptyImage.bottom+10, self.width-2*15, 22)];
_titleLab.textAlignment = NSTextAlignmentCenter;
_titleLab.textColor = [UIColor blackColor];
_titleLab.font = [UIFont systemFontOfSize:16];
_titleLab.text = title;
[self addSubview:_titleLab];
//重试按钮的顶部位置
CGFloat top = _titleLab.bottom;
//显示副标题
_subTitleLab = [[UILabel alloc] initWithFrame:CGRectMake(15, _titleLab.bottom+10, self.width-2*15, 0)];
_subTitleLab.textAlignment = NSTextAlignmentCenter;
_subTitleLab.textColor = [UIColor blackColor];
_subTitleLab.font = [UIFont systemFontOfSize:12];
[self addSubview:_subTitleLab];
if (subTitle.length > 0) {
_subTitleLab.text = subTitle;
_subTitleLab.height = 16;
top = _subTitleLab.bottom;
}
//重试按钮
_retryBtn = [UIButton buttonWithType:UIButtonTypeSystem];
_retryBtn.frame = CGRectMake((self.width-100)/2, top+15, 118, 30);
[_retryBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_retryBtn setBackgroundColor:[UIColor SCBlueColor]];
_retryBtn.titleLabel.font = [UIFont systemFontOfSize:13];
[_retryBtn addTarget:self action:@selector(btnClicked) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_retryBtn];
if (btnTitle.length > 0) {
[_retryBtn setTitle:btnTitle forState:UIControlStateNormal];
}else{
_retryBtn.hidden = YES;
}
}
return self;
}
一般我都会采用下面的方法来创建空视图
+ (SCEmptyView*)emptyViewWithType:(EmptyType)emptyType frame:(CGRect)frame{
if (emptyType == NoneDataEmptyType) {
return [[SCEmptyView alloc] initWithFrame:frame icon:@"ic_no_ticket" title:@"您还没有工单哦" subTitle:@"" buttonTitle:@"返回"];
}else if (emptyType == ErrorEmptyType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"" title:@"页面出错啦~" subTitle:@"" buttonTitle:@""];
}else if (emptyType == NoNetWorkEmptyType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"" title:@"网络无法连接" subTitle:@"请检查你的手机是否联网" buttonTitle:@"重试"];
}else if (emptyType == TimeOutEmptyType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"" title:@"网络请求超时" subTitle:@"" buttonTitle:@"重试"];
}else if (emptyType == NoneSearchDataEmptyType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"" title:@"暂无搜索结果" subTitle:@"" buttonTitle:@""];
}else if (emptyType == LocationErrorEmptyType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"" title:@"无法获取位置信息" subTitle:@"" buttonTitle:@"重试"];
}else if(emptyType == NoInspectionTemplateType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"scInspectionEmptyIcon" title:@"" subTitle:@"目前暂无可以选择的设备及对应的巡检模板" buttonTitle:@""];
}else if(emptyType == NoInspectionTaskType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"scInspectionEmptyTaskIcon" title:@"" subTitle:@"你还没有巡检任务" buttonTitle:@""];
}else if(emptyType == NOOpenDoorDataType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"zanwumen" title:@"" subTitle:@"暂无您可通行的门" buttonTitle:@""];
}else if(emptyType == NORepairRecordDataType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"NORepairRecordImage" title:@"" subTitle:@"暂无维修记录" buttonTitle:@""];
}else if(emptyType == NoBlueToothDoor){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"bluetooth" title:@"暂无附近的门" subTitle:@"" buttonTitle:@""];
}else if(emptyType == NOEMRecordDataType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"NOEMRecordImage" title:@"" subTitle:@"暂无保养记录" buttonTitle:@""];
}else if(emptyType == NoDeviceSelect){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"sc_noDevices" title:@"目前暂无设备" subTitle:@"" buttonTitle:@""];
}else if(emptyType == NoNoticeType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"NOEMRecordImage" title:@"暂无通知数据" subTitle:@"" buttonTitle:@""];
}else if(emptyType == NoAnnounceType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"NOEMRecordImage" title:@"暂无公告数据" subTitle:@"" buttonTitle:@""];
}else if(emptyType == NoPaymentType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"NOEMRecordImage" title:@"暂无收费数据" subTitle:@"" buttonTitle:@""];
}else if(emptyType == NoTicketType){
return [[SCEmptyView alloc] initWithFrame:frame icon:@"NOEMRecordImage" title:@"暂无工单待办数据" subTitle:@"" buttonTitle:@""];
}
return nil;
}
- (void)btnClicked
{
if (_btnClick != nil) {
self.btnClick();
}
}
具体VC中加载空视图的使用方式如下:
-(SCEmptyView *)emptyView{
if (!_emptyView) {
_emptyView = [SCEmptyView emptyViewWithType:NoNoticeType frame:self.view.frame];
}
return _emptyView;
}
比如我在Tabelview上面加载一个空视图,就可以用上面的方式加载View。然后根据数据来管理是否隐藏和展示。
[self.tableView setBackgroundView:self.interactor.dataArrayM.count?[UIView new]:self.emptyView];
或者
第一步:
#pragma mark lazy loading
-(SCEmptyView *)emptyView{
if(!_emptyView){
_emptyView = [SCEmptyView emptyViewWithType:NoInspectionTaskType frame:CGRectMake(0, 50, kSCREEN_WIDTH, kSCREEN_HEIGHT)];
_emptyView.hidden = YES;
}
return _emptyView;
}
第二步:
[self.view addSubview:self.emptyView];
第三步:
self.emptyView.hidden = self.interactor.dataArrayM.count?YES:NO;
以上就是针对项目中常用到的占位图做了一个简单的封装。