iOS 一个标签自动布局的view

最近在做一个关于标签事件统计功能的view ,网上看了一些别人的demo感觉都不合适,于是想着自己造一个轮子探探水。


事件告警统计关注-事件列表.jpg

主要实现图中所示的功能,话不多少搞起!

第一次写大神们多包涵呀
下面这个方法计算传进来的字符串数组,实现每个字符串长度的计算,并做换行判断,每一行存进统计数组中

//将标签数组根据type以及其他参数进行分组装入数组
- (void)disposeTags:(NSArray *)aryName aryCount:(NSArray *)aryCount{
    NSMutableArray *tags = [NSMutableArray new];//纵向数组
    NSMutableArray *subTags = [NSMutableArray new];//横向数组
    
    float originX = _tagOriginX;
    for (NSString *tagTitle in aryName) {
        NSUInteger index = [aryName indexOfObject:tagTitle];
        
        //计算每个tag的宽度
        CGSize contentSize = [tagTitle fdd_sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(self.frame.size.width-_tagOriginX*2, MAXFLOAT)];
        
        NSMutableDictionary *dict = [NSMutableDictionary new];
        dict[@"tagTitle"] = tagTitle;//标签标题
        dict[@"tagCount"] =aryCount[index];
        dict[@"viewWith"] = [NSString stringWithFormat:@"%f",contentSize.width+_tagSpace+30];//标签的宽度
        
        if (index == 0) {
            dict[@"originX"] = [NSString stringWithFormat:@"%f",originX];//标签的X坐标
            [subTags addObject:dict];
        } else {
                if (originX + contentSize.width > self.frame.size.width-_tagOriginX*2) {
                    //当前标签的X坐标+当前标签的长度>屏幕的横向总长度则换行
                    [tags addObject:subTags];
                    //换行标签的起点坐标初始化
                    originX = _tagOriginX;
                    dict[@"originX"] = [NSString stringWithFormat:@"%f",originX];//标签的X坐标
                    subTags = [NSMutableArray new];
                    [subTags addObject:dict];
                } else {
                    //如果没有超过屏幕则继续加在前一个数组里
                    dict[@"originX"] = [NSString stringWithFormat:@"%f",originX];//标签的X坐标
                    [subTags addObject:dict];
                }
            }
        
        if (index +1 == aryName.count) {
            //最后一个标签加完将横向数组加到纵向数组中
            [tags addObject:subTags];
            disposeAry = tags;
        }
        
        //标签的X坐标每次都是前一个标签的宽度+标签左右空隙+标签距下个标签的距离
        originX += contentSize.width+_tagHorizontalSpace+_tagSpace+30;
    }
}

下面这个方法是计算字符串长度的封装方法,只限字符串计算,用的话可以直接搬走

#pragma mark - 扩展方法

@implementation NSString (FDDExtention)

- (CGSize)fdd_sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size {
    CGSize resultSize;
    if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
        NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:@selector(boundingRectWithSize:options:attributes:context:)];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
        [invocation setTarget:self];
        [invocation setSelector:@selector(boundingRectWithSize:options:attributes:context:)];
        NSDictionary *attributes = @{ NSFontAttributeName:font };
        NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin;
        NSStringDrawingContext *context;
        [invocation setArgument:&size atIndex:2];
        [invocation setArgument:&options atIndex:3];
        [invocation setArgument:&attributes atIndex:4];
        [invocation setArgument:&context atIndex:5];
        [invocation invoke];
        CGRect rect;
        [invocation getReturnValue:&rect];
        resultSize = rect.size;
    } else {
        NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:@selector(sizeWithFont:constrainedToSize:)];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
        [invocation setTarget:self];
        [invocation setSelector:@selector(sizeWithFont:constrainedToSize:)];
        [invocation setArgument:&font atIndex:2];
        [invocation setArgument:&size atIndex:3];
        [invocation invoke];
        [invocation getReturnValue:&resultSize];
    }
    return resultSize;
}
字符串长度计算完成了,下面就可以进行所有字符串排列的高度了。其实这个蛮简单的 ,统计数组有多少个元素就代表标签排布有多少行。

//获取处理后的tagsView的高度根据标签的数组

  • (float)getDisposeTagsViewHeight:(NSArray *)ary {

    float height = 0;
    if (disposeAry.count > 0) {
    height = _tagOriginY+disposeAry.count*(_tagHeight+_tagVerticalSpace);
    }
    return height;
    }

下面这个将标签加载到view上了,并实现赋值。

-(void)setTagAryName:(NSArray *)tagAryName aryCount:(NSArray *)aryCount delegate:(id)delegate{
    _tagDelegate=delegate;
    [self disposeTags:tagAryName aryCount:aryCount];
    UILabel *label=[[UILabel alloc]initWithFrame:CGRectMake(_tagOriginX, 0, 200, 30)];
    label.text=@"事件类别统计:";
    label.textColor=_titleColor;
    label.textAlignment=NSTextAlignmentLeft;
    label.adjustsFontSizeToFitWidth=YES;
    [self addSubview:label];
    //遍历标签数组,将标签显示在界面上,并给每个标签打上tag加以区分
    for (NSArray *iTags in disposeAry) {
        NSUInteger i = [disposeAry indexOfObject:iTags];
        
        for (NSDictionary *tagDic in iTags) {
            NSUInteger j = [iTags indexOfObject:tagDic];
            
            NSString *tagTitle = tagDic[@"tagTitle"];
            float originX = [tagDic[@"originX"] floatValue];
            float viewWith = [tagDic[@"viewWith"] floatValue];
            NSString *count = tagDic[@"tagCount"];
            UIView *NCView=[[UIView alloc]initWithFrame:CGRectMake(originX, _tagOriginY+i*(_tagHeight+_tagVerticalSpace), viewWith, _tagHeight)];
            [self addSubview:NCView];
            UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
            button.frame=CGRectMake(0, 0, viewWith-30, _tagHeight);
            button.layer.borderColor = _borderColor.CGColor;
            button.layer.borderWidth = _borderWidth;
            button.layer.masksToBounds = _masksToBounds;
            button.layer.cornerRadius = _cornerRadius;
            button.titleLabel.font = [UIFont systemFontOfSize:_titleSize];
            [button setTitle:tagTitle forState:UIControlStateNormal];
            [button setTitleColor:_titleColor forState:UIControlStateNormal];
            [button setBackgroundImage:_normalBackgroundImage forState:UIControlStateNormal];
            [button setBackgroundImage:_highlightedBackgroundImage forState:UIControlStateHighlighted];
            button.tag = i*iTags.count+j;
            [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
            UILabel *label=[[UILabel alloc]initWithFrame:CGRectMake(viewWith-30, 0, 30, _tagHeight)];
            label.text=[NSString stringWithFormat:@"X%@",count];
            label.textAlignment=NSTextAlignmentCenter;
            label.adjustsFontSizeToFitWidth=YES;
            label.textColor=_titleColor;
            [NCView addSubview:button];
            [NCView addSubview:label];
        }
    }
    self.countLabel=[[UILabel alloc]initWithFrame:CGRectMake(_tagOriginX, [self getDisposeTagsViewHeight:disposeAry], 100, 30)];
    self.countLabel.text=[NSString stringWithFormat:@"总计:%ld次",_times];
    self.countLabel.textAlignment=NSTextAlignmentLeft;
    self.countLabel.adjustsFontSizeToFitWidth=YES;
    self.countLabel.textColor=_titleColor;
    [self addSubview:self.countLabel];
    if (disposeAry.count > 0) {
            float contentSizeHeight = _tagOriginY+disposeAry.count*(_tagHeight+_tagVerticalSpace);
            self.contentSize = CGSizeMake(self.frame.size.width,contentSizeHeight);
    }
    
    if (self.frame.size.height <= 0) {
        self.frame = CGRectMake(CGRectGetMinX([self frame]), CGRectGetMinY([self frame]), CGRectGetWidth([self frame]), [self getDisposeTagsViewHeight:disposeAry]+30);
    }


}

说了这么多,如何调用呢? 那么亮点来了 只需要传进来数组就实现图中的功能。

 
    //计算出全部展示的高度,让maxHeight等于计算出的高度即可,初始化不需要设置高度
NSArray *tagAryCount=@[@"10",@"8",@"7",@"9",@"2",@"4",@"5",@"3",@"4"];
    NSArray* tagAryName = @[@"黑色玫瑰",@"比尔沃吉特",@"钢铁烈阳",@"德玛西亚",@"祖安",@"巨神峰",@"雷瑟守备祖安",@"诺克萨斯暗影岛",@"弗雷尔卓德"];
    ZHLbView * tagsView = [[ZHLbView alloc] initWithFrame:CGRectMake(0, 200, self.view.frame.size.width, 0)];
    [tagsView setTagAryName:tagAryName aryCount:tagAryCount delegate:self];
    [self.view addSubview:tagsView];

补充,在demo编写的过程中 ,遇到了一些小问题,就是scrollView如果是VC的第一个子视图的话 其总是要有一个64高度的空白区。
Demo https://github.com/delegateA/ZHLabelLayout.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,622评论 18 399
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,061评论 25 707
  • 一、自我介绍: 大家好,我是半个西瓜,可以叫我小西。我来自陕西安康,90后,传说中的警花(ps:说这话...
    安小西27阅读 476评论 2 0
  • 我的血已流尽 连接了通往蓝天的路 代表我的树 是把利剑 刺穿蓝天的心脏 女人蜷曲的头发锁紧太阳的愤怒 冰冷的雨的斧...
    心种阅读 362评论 0 2
  • 杨绛先生在《走到人生边上》中谈到人生实苦,她这样说:在这个物欲横流的人世间,人生一世实在是够苦的。你存心做一个与世...
    Innerpeace_4769阅读 2,767评论 0 1