壓縮 UILabel 最后一行的文字

有個需求需要在 UILabel 的最后一行后面放個按鈕怪与,但是需要和 UILabel 內(nèi)對齊壁酬,所以最后一行能顯示的文字就需要進(jìn)行壓縮邓嘹。

場景是文字最多出現(xiàn)三行,如果文字遮擋按鈕(不管文字需要幾行顯示)擅笔,遮擋的文字及前面兩個字符就都進(jìn)行壓縮志衣,變成…

初始思路是直接取最后一行寬度屯援,然后計算多少個文字會擋,然后替換最后的幾個文字念脯。狞洋。

調(diào)研了幾個方法,對英文來說有個比較常見的思路是绿店,每次截取一段文本吉懊,以空格為分界線,然后不斷往里面加詞假勿,直到超出一行的寬度借嗽,把這一行文本加入到一個數(shù)組中,然后在這行文本末尾進(jìn)行切分转培。直到切完整段文本恶导。
效率比較低,而且不適合中文浸须。
參考鏈接:https://stackoverflow.com/questions/10193073/ios-determine-last-line-width-of-uilabel

采用的是這個鏈接里另一個方法惨寿,使用了 NSLayoutManager,計算出整個文本的每行及每個字符的位置删窒,然后通過取最后一個字符的 Index裂垦,使用 lineFragmentRectForGlyphAtIndex:effectiveRange: 方法即可取出該字符所在行的 rect,寬度即在其中肌索。

這個方法看起來有完整的 API 支持蕉拢,決定從這個角度入手。

從另一個回答中看到诚亚,提問者有個類似的需求企量,不過他們是截取第二行的最后幾個字符,不需要考慮只有一行的情況亡电,所以可以用 Magic Number 直接指定 UILabel 中某個 point 的值,然后取出這個 point 的字符 Index硅瞧,進(jìn)行替換即可份乒。

由于我們不是要取所有文本的最后一行,而是取三行內(nèi)的最后一行腕唧,所以這個 Index 就無法簡單的直接取出來了或辖。

解決辦法是使用 enumerateLineFragmentsForGlyphRange 來獲取三行內(nèi)最后一行的 rect,然后和需要截取的位置進(jìn)行比較枣接,如果會發(fā)生文字和按鈕的重疊颂暇,就取重疊點的字符 Index,往前倒推兩個Index但惶,然后把剩下的文字替換…就行了耳鸯。

代碼:

- (NSAttributedString *)truncatingMessage:(NSAttributedString *)message
                                 forLabel:(UILabel *)label
                      truncatingTailWidth:(CGFloat)tailWidth {

    CGSize labelSize = CGSizeMake(label.width, INFINITY);
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    NSTextContainer *container = [[NSTextContainer alloc] initWithSize:labelSize];
    NSTextStorage *storage = [[NSTextStorage alloc] initWithAttributedString:message];
    
    [layoutManager addTextContainer:container];
    [storage addLayoutManager:layoutManager];
    
    container.lineFragmentPadding = 0;
    container.lineBreakMode = label.lineBreakMode;
    container.maximumNumberOfLines = label.numberOfLines;
    
    NSRange range;
    [layoutManager glyphRangeForCharacterRange:NSMakeRange(0, message.length - 1) actualCharacterRange:&range];
    
    __block NSUInteger i = 0;
    __block CGRect lastUsedRect;
    __block NSRange lastGlyphRange;
    
    [layoutManager enumerateLineFragmentsForGlyphRange:range usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) {
        if (i < container.maximumNumberOfLines) {
            lastUsedRect = usedRect;
            lastGlyphRange = glyphRange;
            i += 1;
        } else {
            *stop = YES;
        }
    }];
    
    NSAttributedString *stringToUse = message;
    
    // 最后一行文字寬度會與按鈕重疊才需要處理
    if (lastUsedRect.size.width > label.width - tailWidth) {
        // 算出重疊位置
        CGPoint ellipsisPoint = CGPointMake(label.width - tailWidth, lastUsedRect.origin.y + lastUsedRect.size.height / 2);
        // 重疊位置的字符 Index
        NSUInteger characterIndex = [layoutManager characterIndexForPoint:ellipsisPoint inTextContainer:container fractionOfDistanceBetweenInsertionPoints:nil];
        // 如果往后退兩個字符就到了上一行湿蛔,就不進(jìn)行壓縮了, 這里的 location 指的是最后一行第一個字符的 Index
        if (characterIndex - 2 > lastGlyphRange.location) {
            NSMutableAttributedString *tempString = [[message attributedSubstringFromRange:NSMakeRange(0, characterIndex - 2)] mutableCopy];
            NSDictionary *attributes = [message attributesAtIndex:0 effectiveRange:nil];
            [tempString appendAttributedString:[[NSAttributedString alloc] initWithString:@"…" attributes:attributes]];
            stringToUse = [tempString copy];
        }
    }
    
    return stringToUse;
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末县爬,一起剝皮案震驚了整個濱河市阳啥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌财喳,老刑警劉巖察迟,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異耳高,居然都是意外死亡扎瓶,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門泌枪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來概荷,“玉大人,你說我怎么就攤上這事工闺≌Ш眨” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵陆蟆,是天一觀的道長雷厂。 經(jīng)常有香客問我,道長叠殷,這世上最難降的妖魔是什么改鲫? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮林束,結(jié)果婚禮上像棘,老公的妹妹穿的比我還像新娘。我一直安慰自己壶冒,他們只是感情好缕题,可當(dāng)我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著胖腾,像睡著了一般烟零。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咸作,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天锨阿,我揣著相機(jī)與錄音,去河邊找鬼记罚。 笑死墅诡,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的桐智。 我是一名探鬼主播末早,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼烟馅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了荐吉?” 一聲冷哼從身側(cè)響起焙糟,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎样屠,沒想到半個月后穿撮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡痪欲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年悦穿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片业踢。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡栗柒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出知举,到底是詐尸還是另有隱情瞬沦,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布雇锡,位于F島的核電站逛钻,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏锰提。R本人自食惡果不足惜曙痘,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望立肘。 院中可真熱鬧边坤,春花似錦、人聲如沸谅年。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽融蹂。三九已至旺订,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間殿较,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工桩蓉, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留淋纲,地道東北人。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓院究,卻偏偏與公主長得像洽瞬,于是被迫代替她去往敵國和親本涕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內(nèi)容