iOS开发——无网占位图的实现

作者: Lol刀妹 | 来源:发表于2016-11-05 22:12 被阅读4233次
    T-ara—孝敏

    先来看一下实际效果:

    效果.gif

    为什么要使用无网占位图?

    为了更好地用户体验。难道没网的时候展示一个空白模板?当然,无网占位图也是一个APP最基本的功能只一。

    原理简介:

    viewWillAppear时判断是否有网,如果没网,展示无网占位图。点击无网占位图上的重新查看按钮,判断是否有网,如果没网,toast提示。如果有网,移除无网占位图,重新加载数据。

    详细讲解:

    • 首先按照设计师的UI图封装一个无网占位图view:CQNoNetworkView,在构造方法里完成
    - (instancetype)initWithFrame:(CGRect)frame{
        if (self = [super initWithFrame:frame]) {
            // UI搭建
            [self setUpUI];
        }
        return self;
    }
    
       /** UI搭建 */
      - (void)setUpUI{
        self.backgroundColor = [UIColor whiteColor];
        
        // 404图片放中间
        UIImageView *noNetworkImageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 125, 125)];
        noNetworkImageView.center = CGPointMake(self.width / 2, self.height / 2);
        [self addSubview:noNetworkImageView];
        noNetworkImageView.image = [UIImage imageNamed:@"404notfound"];
        
        // 重新查看按钮
        UIButton *checkButton = [[UIButton alloc]initWithFrame:CGRectMake(0, noNetworkImageView.maxY + 24, 115, 30)];
        checkButton.centerX = self.width / 2;
        [self addSubview:checkButton];
        [checkButton.titleLabel setFont:[UIFont systemFontOfSize:15]];
        checkButton.backgroundColor = [UIColor colorWithRed:0.00 green:0.76 blue:0.66 alpha:1.00];
        [checkButton setTitle:@"重新查看" forState:UIControlStateNormal];
        [checkButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [checkButton addTarget:self action:@selector(checkNetworkButtonClicked) forControlEvents:UIControlEventTouchUpInside];
        
        // 图片上面的两个label
        UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 20)];
        label1.text = @"刷新一下返回店铺!";
        label1.font = [UIFont systemFontOfSize:14];
        label1.textColor = [UIColor colorWithRed:0.00 green:0.77 blue:0.68 alpha:1.00];
        label1.backgroundColor = [UIColor clearColor];
        label1.textAlignment = NSTextAlignmentCenter;
        [label1 sizeToFit];
        label1.centerX = self.width / 2;
        label1.maxY = noNetworkImageView.y - 21;
        [self addSubview:label1];
        
        UILabel *label2 = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 15)];
        label2.text = @"您似乎迷路了";
        label2.font = [UIFont systemFontOfSize:19];
        label2.textColor = [UIColor colorWithRed:0.00 green:0.77 blue:0.67 alpha:1.00];
        label2.backgroundColor = [UIColor clearColor];
        label2.textAlignment = NSTextAlignmentCenter;
        [label2 sizeToFit];
        label2.centerX = self.width / 2;
        label2.maxY = label1.y - 12;
        [self addSubview:label2];
    }
    

    • 处理“重新查看”按钮的逻辑,基本思路是:点击此按钮时,判断是否有网,如果仍旧没网,弹出toast提示用户;如果有网,移除此view,并且,让代理方执行相应代理方法,比如说,重新加载数据。
     /** 重新查看按钮点击 */
      - (void)checkNetworkButtonClicked{
        if ([DateUtil isNetWorkRunning]) {
            // 如果有网,view消失,并且让代理方执行代理方法
            for (CQNoNetworkView *view in [self getCurrentViewController].view.subviews) {
                if ([view isMemberOfClass:[CQNoNetworkView class]]) {
                    [view removeFromSuperview];
                }
            }
            
            // 重新加载数据
            if ([self.delegate respondsToSelector:@selector(reloadData)]) {
                [self.delegate reloadData];
            }
        }else{
            // 如果没网,toast提示
            [CQHud showToastWithMessage:@"请检查你的网络连接"];
        }
    }
    

    • 确定代理方法(点击“重新加载”按钮时,代理方执行的方法),我的是重新加载数据。
    @protocol CheckNetworkDelegate <NSObject>
    @optional
    
      /** 重新加载数据 */
      - (void)reloadData;
    
    @end
    
      /** 无网络时展示的view */
    @interface CQNoNetworkView : UIView
    
    @property (nonatomic,weak) id<CheckNetworkDelegate> delegate;
    
    @end
    

    • 确定代理方。代理方就是执行“重新加载数据”的对象。由于每个viewController都需要在无网时展示无网占位图,所以代理方可以设置为项目的BaseViewController(不要告诉我,你的项目里没有基类😅)
    @interface BaseViewController ()<CheckNetworkDelegate>
    

    在基类里实现重新加载数据,当然,需要由子类重写,不过如果你的项目架构的比较好,所有viewcontroller的获取数据的方法的方法名都一样,那么就不需要再由子类重写了:

    /** 重新加载数据,由子类重写 */
         (void)reloadData{
        
    }
    

    同样在基类里实现弹出无网占位图的方法:

    /** 显示无网络view */
    - (void)showNoNetworkView{
        // 将导航栏和tabbar留出来
        CQNoNetworkView *noNetworkView = [[CQNoNetworkView alloc]initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight - 49)];
        noNetworkView.delegate = self;
        [self.view addSubview:noNetworkView];
    }
    
    • 在基类的viewWillAppear:里判断网络情况:
    // 如果没网,加载无网占位图
        if (![DateUtil isNetWorkRunning]) {
            // 无网加载无网站位图
            [self showNoNetworkView];
        }else{
            // 有网移除所有无网展位图
            for (CQNoNetworkView *view in self.view.subviews) {
                if ([view isMemberOfClass:[CQNoNetworkView class]]) {
                    [view removeFromSuperview];
                }
            }
        }
    
    • 最后,在你的子类里重写“重新加载数据”方法即可:
    - (void)reloadData{
        [self getData];
    }
    
    

    总结

    此功能主要是代理和基类的运用,合理使用基类能让你少些很多代码。当然有些APP可能不仅有一种网络占位图,这个时候在子类里重写基类里的showNoNetworkView方法即可。以上是我对此功能的一些个人看法,只是简单的实现了这个功能,具体项目中还是要根据项目需求进行必要修改和优化的。但是,思路基本上不变。欢迎各位看官提出意见或建议。

    补充两个更加优雅和强大的Demo

    UITableView空数据占位图
    适用于任何场景的通用占位图

    相关文章

      网友评论

      • 我是C:多个界面怎么统一处理
        Lol刀妹:@嘴爷 可以,这个是对view的封装
        嘴爷:https://github.com/dzenbot/DZNEmptyDataSet
        Lol刀妹:每个界面继承基类,基类里面写好这个方法。
      • 爱阿爸的阿龙龙:码走 借用下 嘻嘻
        Lol刀妹:@爱阿爸的阿龙龙868 :sweat_smile:
      • 十一岁的加重:顶图好漂亮,还 有没有类似 的啊
        Lol刀妹:@十一岁的加重 去我的主页,你会看到很多类似的:smile:
      • Joy___:妹子可以
        Lol刀妹:@Joy___ :sweat_smile:
      • 柳骏:想要你这个小demo的源码,有提供github下载网址吗:blush:
        Lol刀妹:https://github.com/wyzxc/CQPlaceholderView
        https://github.com/wyzxc/TableViewNoContentView
        抱歉来晚了:sweat_smile:
      • humanff:[DateUtil isNetWorkRunning]这个方法能看下怎么写
        Lol刀妹:@humanff 在APPDelegate里面就把监控开启
        humanff:@无夜之星辰 这个Reachability类是异步的把
        Lol刀妹:@humanff 这就是一个判断是否有网络的。
        + (BOOL)isNetWorkRunning{
        BOOL isExistenceNetwork=YES;
        Reachability *r = [Reachability reachabilityWithHostName:@"www.apple.com"];//auto-view.cn/iphone
        switch ([r currentReachabilityStatus]) {
        case NotReachable:
        isExistenceNetwork=NO;
        break;
        case ReachableViaWWAN:
        //使用3G/GPRS网络
        isExistenceNetwork=YES;
        break;
        case ReachableViaWiFi:
        //使用WiFi网络
        isExistenceNetwork=YES;
        break;
        }
        return isExistenceNetwork;
        }
      • 向钱冲啊:直接判断数据源为空不也可以么?如果是tableview和collectionView的话直接backgroundview=自定义view占位图?
        Lol刀妹:@向钱冲啊 木有缓存:sweat_smile:
        向钱冲啊:@无夜之星辰 可是楼主大大,我觉得数据源为空才是标准啊。为什么要显示占位图,不就是界面没数据才显示占位图的么?就算没网,可以我有缓存,这时候没必要显示占位图啊。这才是正常套路吧。 :sweat:
        Lol刀妹:@向钱冲啊 数据源为空,不一定代表没网。建议还是按照正常的套路来。
      • qiongyong:图片可以的 :smile:
        Lol刀妹:@qiongyong 孝敏,必须可以:sunglasses:
      • 男人宫:兄弟,demo也整出来啊 :smiley:
        男人宫:@无夜之星辰 我也想做你这样的效果,但我项目中确实没用你说的基类,你所说的基类,就是所有的VC都要继承的这个类吧,所以有点懵逼,那我该怎么处理呢
        男人宫:@无夜之星辰 写的不错,必须支持,不过就是少个demo,再有个demo就堪称完美 :stuck_out_tongue_winking_eye:
        Lol刀妹:@ios小霸王 我记得你,你是第一个关注我的人:smile:
      • FR_Zhang:这个跟SDWebImage的placeholderImage有什么区别吗
        Lol刀妹:@FR_Zhang 我这个占位图实际上是一个带特定功能的自定义view,而不是图片:smile:
        FR_Zhang:@无夜之星辰 因为绝大多数的图片缓存采用sd。sd有个展位图的方法。我主要是想知道。这个展位图 和sd的展位图有何区别
        Lol刀妹:@FR_Zhang 我实在不清楚这个跟SD有什么联系:sweat_smile:
      • 七里小晴天:图片不错
        Lol刀妹:@七里小晴天 访问量+1:sweat_smile:
      • 超_iOS:还有这东西,一直没意识到
        Lol刀妹:@_超 这东西不能忽略掉哦:smile:
      • macfai:赞一个,楼主能把demo共享一下吗?多谢:smile:
        Lol刀妹:demo已添加:sweat_smile:
        macfai:@无夜之星辰 好吧,:smile:
        Lol刀妹:@macfai 汗,代码都那么详细咯:sweat_smile:
      • 钱刀为:好得很
        Lol刀妹:@南人在外 四川人:sweat_smile:

      本文标题:iOS开发——无网占位图的实现

      本文链接:https://www.haomeiwen.com/subject/nolguttx.html