iOS 獲取固定寬度下的可見(jiàn)字符串

我們知道當(dāng)UILabel顯示不下內(nèi)容時(shí),會(huì)自動(dòng)截?cái)嗵幚?,我們還可以用lineBreakMode來(lái)修改截?cái)喾绞?。?dāng)我們限定只能截?cái)嗄承┳址麜r(shí),系統(tǒng)提供的截?cái)喾绞骄筒荒軡M足了。

自定義截?cái)嘧址麜r(shí),就會(huì)遇到一個(gè)問(wèn)題,固定寬度下能顯示多少字符串?

使用場(chǎng)景

偶爾收到了微信的專屬紅包,發(fā)現(xiàn)當(dāng)微信名或備注較長(zhǎng)時(shí),會(huì)將用戶名截?cái)囡@示。

微信專屬紅包,昵稱較長(zhǎng)時(shí)顯示如下:

給ABCDEFGHI...的專屬紅包
ABCDEFGHI...已領(lǐng)取

實(shí)現(xiàn)邏輯分析

微信紅包氣泡寬度是相對(duì)固定的,所以紅包狀態(tài)的寬度也是固定的。當(dāng)用戶名過(guò)長(zhǎng)時(shí),要保證其他字符能完整顯示,只能截?cái)嘤脩裘?/p>

//其他字符
給xxx的專屬紅包

總寬度 = 其他字符寬度 + 用戶名寬度(可截?cái)啵?

由上我們知道,算出其他字符的寬度后,就能得到用戶名寬度。拿到用戶名可顯示的寬度后,怎么知道能顯示多少內(nèi)容呢?

實(shí)現(xiàn)流程

查資料發(fā)現(xiàn)可以用CTFrame獲取可見(jiàn)字符串范圍 CTFrameGetVisibleStringRange

CFRange CTFrameGetVisibleStringRange(CTFrameRef frame);

由上定義,我們還需要?jiǎng)?chuàng)建一個(gè)CTFrameRef,需用到 CTFramesetterCreateFrame

CTFrameRef CTFramesetterCreateFrame(CTFramesetterRef framesetter, CFRange stringRange, CGPathRef path, CFDictionaryRef frameAttributes);

通過(guò)path參數(shù),我們可以傳入寬度限制,即可得到固定寬度下的可見(jiàn)字符串范圍。

上代碼

最好寫(xiě)在NSStringCategory中,需要導(dǎo)入CoreText框架。

注意:其中path的高度需大于font.lineHeight,小于2倍font.lineHeight,當(dāng)大于2倍font.lineHeight時(shí),將按照多行來(lái)計(jì)算可顯示的內(nèi)容。

#import "NSString+STExtension.h"
#import <CoreText/CoreText.h>


/// 獲取固定寬度下的可見(jiàn)字符串
/// @param width 寬度
/// @param font 字體
/// @param showEllipsis 結(jié)尾是否展示省略號(hào)
- (NSString *)getVisibleStringWithWidth:(CGFloat)width font:(UIFont*)font showEllipsis:(bool)showEllipsis
{
    if (width == 0) {
        return @"";
    }
    NSMutableParagraphStyle *p = [[NSMutableParagraphStyle alloc] init];
    p.lineBreakMode = NSLineBreakByCharWrapping;
    
    NSAttributedString *namesAtt = [[NSAttributedString alloc] initWithString:self attributes:@{NSFontAttributeName:font, NSParagraphStyleAttributeName:p}];
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)namesAtt);
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, width, font.lineHeight + 1.0)];
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, self.length), path.CGPath, NULL);
    
    CFRange range = CTFrameGetVisibleStringRange(frame);
    CFRelease(framesetter);
    CFRelease(frame);
    NSString *resultStr = [self substringWithRange:NSMakeRange(range.location, range.length)];
    if (showEllipsis && resultStr.length < self.length && resultStr.length > 0) {
        resultStr = [resultStr stringByReplacingCharactersInRange:NSMakeRange(resultStr.length - 1, 1) withString:@"..."];
    }
    return resultStr;
}

最后

感謝閱讀,有問(wèn)題歡迎討論。

參考文章:NSString根據(jù)寬度獲得能顯示出的字符串

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容