• 代码优化之减少重复代码-实践


    背景

    在APP中列表是一种比较常见的数据展示方式,当有数据时,就显示数据;如果没有数据,一般不会显示一个空白页面,而是在空白页面上加一些提示信息,比如像下面这样:

    不同的APP会有不同的设计,但不管是什么样的设计,它在整个APP内部应该是一致的,要变也只是文字或图片稍有不同。

    现状

    因为我们目前的项目还算比较庞大,所以这种列表无数据的情况出现了20多次,所以类似下面的代码出现了就有20多次。为什么说类似,因为是由不同的人写的,逻辑也是差不多,但真的各不相同,有的封装成一个方法,比如:setNoMessageView,有的直接写在viewDidLoad里面......

    - (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方法。

    + (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;
    }

    调用:

    - (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。

    @interface UITableView(EmptyView)
    
    @property (nonatomic, strong, readonly) UIView *emptyView;
    
    -(void)addEmptyViewWithImageName:(NSString*)imageName title:(NSString*)title;
    
    @end
    static char UITableViewEmptyView;
    
    @implementation UITableView(EmptyView)
    
    @dynamic emptyView;
    
    - (UIView *)emptyView
    {
        return objc_getAssociatedObject(self, &UITableViewEmptyView);
    }
    
    - (void)setEmptyView:(UIView *)emptyView
    {
        [self willChangeValueForKey:@"HJEmptyView"];
        objc_setAssociatedObject(self, &UITableViewEmptyView,
                                 emptyView,
                                 OBJC_ASSOCIATION_ASSIGN);
        [self didChangeValueForKey:@"HJEmptyView"];
    }
    
    
    -(void)addEmptyViewWithImageName:(NSString*)imageName title:(NSString*)title
    {
        if (!self.emptyView)
        {
            CGRect frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
            UIImage* image = [UIImage imageNamed:imageName];
            NSString* text = title;
    
            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];
    
            [self addSubview:noMessageView];
    
            self.emptyView = noMessageView;
        }
    
    }
    
    @end

    然后外部调用就很简单了,没有额外的属性,而且一句话就搞定。

    [self.shopListView.shopListTableView addEmptyViewWithImageName:@"no_message.png" title:@"Dear, no information"];

    然后在加载数据前进行判定是否显示emptyView

    self.shopListView.shopListTableView.emptyView.hidden = ([self.dataArray count] != 0);
  • 相关阅读:
    mac下配置adb环境变量
    Flutter——多行文字展开收起
    sourceTree报错:Updates were rejected because the tag already exists in the remote.
    股市赚钱就是这么简单
    鸿蒙手机版JNI实战(JNI开发、SO库生成、SO库使用)
    Mybatis、Mybatis Generator、Mybatis-Plus、Mybatis Plus Generator
    鸿蒙运行报错:Failure[INSTALL_PARSE_FAILED_USESDK_ERROR] Error while Deploying HAP
    MAC 下Android ROM 提取文件
    IDAPython 插件开发
    Android ollvm 集成
  • 原文地址:https://www.cnblogs.com/yulang314/p/5084372.html
Copyright © 2020-2023  润新知