需求背景:
年中促銷活動,需要添加一個標(biāo)簽讓用戶知道這個是促銷商品毅待。
我的想法
這很簡單的尚卫, 根據(jù)接口返回信息,是否顯示標(biāo)簽圖片就好了嘛尸红。 后來證實我還是太年輕吱涉。。外里。
標(biāo)簽樣式
經(jīng)過UI設(shè)計師給出幾個版本怎爵,最后給了一個在標(biāo)題前面插入一個標(biāo)簽的樣式。 注意: 這個標(biāo)簽不是一個圖片盅蝗,不是圖片鳖链。 是一個文本外加虛線邊框。樣式如圖:
乍一看這很簡單啊墩莫,兩個控件而已嘛芙委, 最多在第一個控件那里畫一個虛線邊框。狂秦。 但是: 實際情況不是這樣的灌侣, 后面的標(biāo)題可能有兩行!A盐省侧啼! 下一行開始要和標(biāo)簽對齊。堪簿。痊乾。
第一反應(yīng)我是拒絕的,找設(shè)計師修改原型圖戴甩。我給出幾個方案:
方案1:模仿淘寶符喝,將標(biāo)簽用中括號包起來凸顯。
天貓標(biāo)簽.png
這個字體甜孤、樣式协饲、顏色都可以隨便改, 你想怎么凸顯都行缴川。茉稠。但是產(chǎn)品不同意, 特么的換把夸。
方案2:將標(biāo)簽做成圖片而线,直接嵌套在前面。
設(shè)計師不給做, 說是有多語言膀篮,太多了嘹狞。。 還特么不行誓竿。
方案N磅网。。 都特么不行筷屡。涧偷。
產(chǎn)品說了,我不管你們怎么做毙死,反正樣式就這樣了定了燎潮。 我反饋說不好實現(xiàn)等等, 人家回一句扼倘, 京東是可以的叭贩狻!0π俊隅肥! 心里一萬只曹尼瑪奔騰跑過啊。
既然定下來這樣了袄简, 只能硬著頭皮試試腥放。
實現(xiàn)方法
方法一:
最笨的方法: 計算標(biāo)簽字符串占據(jù)的位置, 將標(biāo)題前面用空格補上相應(yīng)的字符串占據(jù)位置绿语,再講標(biāo)簽控件放到最前面覆蓋秃症。
這個不到萬不得已我是不用的哈。吕粹。
方法二: 自定義封裝控件
1.設(shè)置三個控件种柑。
控件一:標(biāo)簽;
控件二:右側(cè)標(biāo)題匹耕;
控件三:下面從標(biāo)簽開始的標(biāo)題Label聚请。(但是這個可能沒有。)
效果圖如下:
這里面有幾個困難點:
1.控件二顯示文本多少稳其,最后一個字符是哪個驶赏。
2.怎么確定有沒有第二行標(biāo)題控件。
3.第二個控件的起始字符怎么計算既鞠。
實現(xiàn)方案
寫了一個分類煤傍,算出具體每行顯示的字符,將其保存在一個數(shù)組中嘱蛋,當(dāng)數(shù)組個數(shù)大于1的時候蚯姆,就有第二個控件五续。也即可以確定第二個控件的其實字符。
寫了一個分類龄恋,傳入第一行標(biāo)題的Label計算疙驾。代碼如下:
注意:這個方法計算很多英文文本的時候,可能不太準(zhǔn)確
- (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;
}
具體項目布局實現(xiàn)篙挽, 這個是demo荆萤,項目本身用Masonry布局,簡單一些铣卡。 下面代碼共參考:
- (void)resetViewsConstraints {
//1.計算標(biāo)簽label的大小
self.preLabel.frame = CGRectMake(0, 0, self.preLabel.intrinsicContentSize.width + 5, self.preLabel.intrinsicContentSize.height);
//2.計算標(biāo)題
self.titleLabel.frame = CGRectMake(0, 0, self.view.frame.size.width - CGRectGetMaxX(self.preLabel.frame), self.titleLabel.intrinsicContentSize.height);
//3. 看標(biāo)題到底有多少 ==== 1>.一行, 就這樣布局 2>.多行偏竟, 添加subLabel煮落, 計算subLabel的第一個字符是什么
// CGFloat count = self.titleLabel.intrinsicContentSize.height / self.titleLabel.font.lineHeight;
// if (count > 1) {
// [self.backGorundLabel addSubview:self.subLabel];
// }
//標(biāo)題行數(shù) 字符串?dāng)?shù)組
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));
}
}
以上就是我自己想到實現(xiàn)的方法∮荒保可能有點挫蝉仇,但是能滿足產(chǎn)品需求了。殖蚕。
更優(yōu)方案
方法三:首行縮進方法
對接上面代碼過程中轿衔, 想到了一個更好的辦法。也是基于方法一的改進睦疫。
既然能計算出標(biāo)簽控件的大小害驹, 那我使用首行縮進方法不就完美解決了嘛。蛤育。 O(∩_∩)O哈哈~ 哈哈哈哈 容我笑一會哈宛官。 實現(xiàn)demo:
首先計算控件的大小來確定首行縮進距離, 多語言也沒有問題瓦糕。
其次計算縮進用的富文本字典底洗。
最后直接將標(biāo)題設(shè)置為富文本,將標(biāo)簽控件放在最前面即可咕娄。
//標(biāo)簽寬度亥揖,即縮進距離。 這里為了更好的展示圣勒,加了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];
//設(shè)置標(biāo)題
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;
}
結(jié)束
至此檀葛,這個看似很簡單的需求完成了。這個功能應(yīng)該很多平臺都會用颅和,可以借鑒參考阻课, 有更好的方案,也希望告知旁趟,感謝昼激。
結(jié)語
遇到問題不要抗拒庇绽, 試著去解決。 沒有解決不了的問題橙困!
方案有N多種瞧掺,不要滿足,試著找更優(yōu)的方案凡傅。