50行程式碼實現圖文混排

哈雷哈雷_Wong發表於2019-03-01

棄坑簡書,從簡書搬家到掘金,正好把之前這篇文章改為Markdown模式。

開頭

本文是技術集中的第一篇技術性文章,所以就記錄一點簡單且淺顯易懂的東西。

現在即時通訊和朋友圈這兩塊功能基本上屬於app的標配功能了吧。圖文混排在這兩塊中使用最為常見,我已經做好了demo:圖文混排Demo

文中會講述幾點小技巧:圖文混排、動態計算文字長度、圖片拉伸方法。

以前的做法

在以前做圖文混排的時候,經常使用OHAttributedLabel,後來蘋果吸取了一些第三方的優點,對NSString做了擴充套件,作者也不再更新,推薦用系統的方法來實現圖文混排。具體請自行百度或者google關鍵字OHAttributedLabel

現在的做法

蘋果在iOS7中推出了一個新的類NSTextAttachment,它是做圖文混排的利器,本文就是用這個類,只用50行程式碼實現文字與表情混排,當然也可以實現段落中的圖文混排,與CoreText比起來實在是簡單了太多,下面講述兩個案例。(更新:YYKit中的YYTextAttachment,應該就是從NSTextAttachment上找的靈感吧)

案例一

先上效果圖,聊天介面中的圖文混排

50行程式碼實現圖文混排

要實現這樣的效果,code4app上似乎有很多種做法,還有一些奇葩的一個字元一個label,但是今天要講述的做法,是目前為止我看到的最簡單的做法了,只用一個UILabel,需要用到UILabel的attributedText屬性。

首先,需要組裝一個表情和文字對應的plist檔案,plist中的鍵值對如下:

50行程式碼實現圖文混排

本文用一個工具類來實現一個轉換的方法,你也可以給NSString新增一個類別來實現。

第一步,解析plist檔案,轉化為陣列。

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"emoticons" ofType:@"plist"];
NSArray *face = [NSArray arrayWithContentsOfFile:filePath];
複製程式碼

第二步,將字串轉換為可變屬性字串,並通過正規表示式匹配出所有的要替換的字元。

//1、建立一個可變的屬性字串
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:text];
//2、通過正規表示式來匹配字串
NSString *regex_emoji = @"\\[[a-zA-Z0-9\\/\\u4e00-\\u9fa5]+\\]";//匹配表情
NSError *error =nil;
NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:regex_emoji options:NSRegularExpressionCaseInsensitive error:&error];
if (!re) {
    NSLog(@"%@", [errorlocalizedDescription]);
    return attributeString;
}
NSArray *resultArray = [rematchesInString:text options:0 range:NSMakeRange(0, text.length)];
複製程式碼

陣列中都是NSTextCheckingResult物件,它包含了特殊字元在整個字串中的位置等資訊。

第三步,將特殊字元與對應表情關聯

NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:resultArray.count];
//根據匹配範圍來用圖片進行相應的替換
for(NSTextCheckingResult *match in resultArray) {
    //獲取陣列元素中得到range
    NSRangerange = [match range];
    //獲取原字串中對應的值
    NSString*subStr = [text substringWithRange:range];
    for(inti =0; i < face.count; i ++) {
        if ([face[i][@"cht"] isEqualToString:subStr]) {
            //face[i][@"png"]就是我們要載入的圖片
            //新建文字附件來存放我們的圖片,iOS7才新加的物件
            NSTextAttachment*textAttachment = [[NSTextAttachment alloc] init];
            //給附件新增圖片
            textAttachment.image = [UIImage imageNamed:face[i][@"png"]];
            //調整一下圖片的位置,如果你的圖片偏上或者偏下,調整一下bounds的y值即可
            textAttachment.bounds = CGRectMake(0, -8, textAttachment.image.size.width, textAttachment.image.size.height);
            //把附件轉換成可變字串,用於替換掉源字串中的表情文字
            NSAttributedString*imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment];
            //把圖片和圖片對應的位置存入字典中
            NSMutableDictionary*imageDic = [NSMutableDictionary dictionaryWithCapacity:2];
            [imageDic setObject:imageStr forKey:@"image"];
            [imageDic setObject:[NSValuevalueWithRange:range] forKey:@"range"];
            //把字典存入陣列中
            [imageArray addObject:imageDic];
        }
    }
}
複製程式碼

第四步,將特殊字元替換成圖片

// 4、從後往前替換,否則會引起位置問題
for (int i = (int)imageArray.count-1; i >=0; i--) {
    NSRange range;
    [imageArray[i][@"range"] getValue:&range];
    //進行替換
    [attributeString replaceCharactersInRange:range withAttributedString:imageArray[i][@"image"]];
}
複製程式碼

用法:

NSString *content = @"文字加上表情[得意][酷][呲牙]";
NSMutableAttributedString *attrStr = [Utility emotionStrWithString:content];
_contentLabel.attributedText= attrStr;
複製程式碼

案例二

50行程式碼實現圖文混排

需要實現的效果:

有了上面的方法,這個效果更容易實現,只需要將某些圖片給它設定一個固定的字元對應即可。

與以上方法主要不同點在於正規表示式:

//2、匹配字串
NSError *error = nil;
NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:string options:NSRegularExpressionCaseInsensitive error:&error];
if (!re) {
    NSLog(@"%@", [error localizedDescription]);
    return attributeString;
}
複製程式碼

用法:

NSString *praiseStr = @"路人甲、路人乙";
NSString *praiseInfo = [NSStringstringWithFormat:@"<點贊> %@",praiseStr];
NSDictionary *attributesForAll = @{NSFontAttributeName:[UIFontsystemFontOfSize:14.0],NSForegroundColorAttributeName:[UIColorgrayColor]};

NSMutableAttributedString *attrStr = [Utility exchangeString:@"<點贊>" withText:praiseInfoimageName:@"dynamic_love_blue"];
複製程式碼

彩蛋

1、計算動態文字的長度

NSMutableAttributedString *content = [Utility emotionStrWithString:_dynamic.text];
[content addAttribute:NSFontAttributeName value:kContentFont  range:NSMakeRange(0, content.length)];
CGSize maxSize = CGSizeMake(kDynamicWidth,MAXFLOAT);
CGSize attrStrSize = [content boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;
複製程式碼

其中NSMutableAttributedString型別的字串可以新增多種屬性,並且在計算的時候必須設定字元大小等屬性。

2、圖片拉伸

在iOS5之前可以用stretchableImageWithLeftCapWidth: topCapHeight:

iOS5之中用resizableImageWithCapInsets:

iOS6開始多了一個引數resizableImageWithCapInsets:resizingMode:

相關文章