美文网首页iOS开发实战笔记iOS开发
标题前面嵌入非图片标签需求

标题前面嵌入非图片标签需求

作者: Eddiegooo | 来源:发表于2018-06-20 17:14 被阅读64次

    需求背景:

    年中促销活动,需要添加一个标签让用户知道这个是促销商品。

    我的想法

    这很简单的, 根据接口返回信息,是否显示标签图片就好了嘛。 后来证实我还是太年轻。。。

    标签样式

    经过UI设计师给出几个版本,最后给了一个在标题前面插入一个标签的样式。 注意: 这个标签不是一个图片,不是图片。 是一个文本外加虚线边框。样式如图:

    UI样式图.png
    乍一看这很简单啊,两个控件而已嘛, 最多在第一个控件那里画一个虚线边框。。 但是: 实际情况不是这样的, 后面的标题可能有两行!!! 下一行开始要和标签对齐。。。

    第一反应我是拒绝的,找设计师修改原型图。我给出几个方案:

    方案1:模仿淘宝,将标签用中括号包起来凸显。


    天猫标签.png

    这个字体、样式、颜色都可以随便改, 你想怎么凸显都行。。但是产品不同意, 特么的换。

    方案2:将标签做成图片,直接嵌套在前面。
    设计师不给做, 说是有多语言,太多了。。 还特么不行。

    方案N。。 都特么不行。。
    产品说了,我不管你们怎么做,反正样式就这样了定了。 我反馈说不好实现等等, 人家回一句, 京东是可以的啊!!! 心里一万只曹尼玛奔腾跑过啊。

    既然定下来这样了, 只能硬着头皮试试。

    实现方法

    方法一:

    最笨的方法: 计算标签字符串占据的位置, 将标题前面用空格补上相应的字符串占据位置,再讲标签控件放到最前面覆盖。
    这个不到万不得已我是不用的哈。。

    方法二: 自定义封装控件

    1.设置三个控件。
    控件一:标签;
    控件二:右侧标题;
    控件三:下面从标签开始的标题Label。(但是这个可能没有。)
    效果图如下:


    模拟图.png

    这里面有几个困难点:
    1.控件二显示文本多少,最后一个字符是哪个。
    2.怎么确定有没有第二行标题控件。
    3.第二个控件的起始字符怎么计算。

    实现方案

    写了一个分类,算出具体每行显示的字符,将其保存在一个数组中,当数组个数大于1的时候,就有第二个控件。也即可以确定第二个控件的其实字符。
    写了一个分类,传入第一行标题的Label计算。代码如下:
    注意:这个方法计算很多英文文本的时候,可能不太准确

    - (NSArray *)getSeparatedLinesFromLabel:(UILabel *)label
    {
        NSString *text = [label text];
        UIFont   *font = [label font];
        CGRect    rect = [label frame];
        
        CTFontRef myFont = CTFontCreateWithName((__bridge CFStringRef)([font fontName]), [font pointSize], NULL);
        NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text];
        [attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)];
        
        CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attStr);
        
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000));
        
        CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
        
        NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame);
        NSMutableArray *linesArray = [[NSMutableArray alloc]init];
        
        for (id line in lines)
        {
            CTLineRef lineRef = (__bridge CTLineRef )line;
            CFRange lineRange = CTLineGetStringRange(lineRef);
            NSRange range = NSMakeRange(lineRange.location, lineRange.length);
            
            NSString *lineString = [text substringWithRange:range];
            [linesArray addObject:lineString];
        }
        return (NSArray *)linesArray;
    }
    

    具体项目布局实现, 这个是demo,项目本身用Masonry布局,简单一些。 下面代码共参考:

    - (void)resetViewsConstraints {
        //1.计算标签label的大小
        self.preLabel.frame = CGRectMake(0, 0, self.preLabel.intrinsicContentSize.width + 5, self.preLabel.intrinsicContentSize.height);
        
        //2.计算标题
        self.titleLabel.frame = CGRectMake(0, 0, self.view.frame.size.width - CGRectGetMaxX(self.preLabel.frame), self.titleLabel.intrinsicContentSize.height);
        
        //3. 看标题到底有多少 ==== 1>.一行, 就这样布局  2>.多行, 添加subLabel, 计算subLabel的第一个字符是什么
    //     CGFloat count = self.titleLabel.intrinsicContentSize.height / self.titleLabel.font.lineHeight;
    //    if (count > 1) {
    //        [self.backGorundLabel addSubview:self.subLabel];
    //    }
        //标题行数 字符串数组
        NSArray *lineStrArray = [self getSeparatedLinesFromLabel:self.titleLabel];
        
        if (lineStrArray.count > 2) {
            [self.backGorundLabel addSubview:self.subLabel];
            self.titleLabel.text = lineStrArray[0];
            NSMutableString *lineStr = [NSMutableString string];
            [lineStrArray enumerateObjectsUsingBlock:^(NSString *text, NSUInteger idx, BOOL * _Nonnull stop) {
                if (idx > 0) {
                    [lineStr appendString:text];
                }
            }];
            self.subLabel.text = lineStr;
            self.subLabel.frame = CGRectMake(0, CGRectGetMaxY(self.titleLabel.frame), self.view.frame.size.width, 30);
            self.backGorundLabel.frame = CGRectMake(0, 100, self.view.frame.size.width, CGRectGetMaxY(self.subLabel.frame));
        }else {
            self.backGorundLabel.frame = CGRectMake(0, 100, self.view.frame.size.width, CGRectGetMaxY(self.titleLabel.frame));
        }
    }
    
    

    以上就是我自己想到实现的方法。可能有点挫,但是能满足产品需求了。。

    更优方案
    方法三:首行缩进方法

    对接上面代码过程中, 想到了一个更好的办法。也是基于方法一的改进。
    既然能计算出标签控件的大小, 那我使用首行缩进方法不就完美解决了嘛。。 O(∩_∩)O哈哈~ 哈哈哈哈 容我笑一会哈。 实现demo:


    首行缩进.png

    首先计算控件的大小来确定首行缩进距离, 多语言也没有问题。
    其次计算缩进用的富文本字典。
    最后直接将标题设置为富文本,将标签控件放在最前面即可。

        //标签宽度,即缩进距离。 这里为了更好的展示,加了10的偏移量
        CGFloat headIndent = [self.preLabel sizeThatFits:CGSizeMake(self.preLabel.intrinsicContentSize.width, 200)].width + 10;
    
        //缩进富文本
        NSDictionary *attDict = [self settingAttributesWithLineSpace:5.0f FirstLineHeadIndent:headIndent LabelFont:[UIFont systemFontOfSize:14.0] LabelTextColor:self.titleLabel.textColor];
    
        NSAttributedString *string = [[NSAttributedString alloc] initWithString:self.titleString attributes:attDict];
        //设置标题
        self.titleLabel.attributedText = string;
    

    这里面有一个缩进富文本分类方法:

    - (NSDictionary *)settingAttributesWithLineSpace:(CGFloat)lineSpace FirstLineHeadIndent:(CGFloat)headIndent LabelFont:(UIFont *)font LabelTextColor:(UIColor *)textColor; {
        //分段样式
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        //行间距
        paragraphStyle.lineSpacing = lineSpace;
        //首行缩进
        paragraphStyle.firstLineHeadIndent = headIndent;
        //富文本样式
        NSDictionary *attributeDic = @{
                                       NSFontAttributeName : font,
                                       NSParagraphStyleAttributeName : paragraphStyle,
                                       NSForegroundColorAttributeName : textColor
                                       };
        return attributeDic;
    }
    

    结束

    至此,这个看似很简单的需求完成了。这个功能应该很多平台都会用,可以借鉴参考, 有更好的方案,也希望告知,感谢。

    结语

    遇到问题不要抗拒, 试着去解决。 没有解决不了的问题!
    方案有N多种,不要满足,试着找更优的方案。

    相关文章

      网友评论

      本文标题:标题前面嵌入非图片标签需求

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