关于YYTextView的一些想法

最近因为项目原因,需要完成类似微博的@功能,用了一下YYTextView。

注意点: UIViewContoller直接使用YYTextView是会报错的,提示:exception:Application windows are expected to have a root view controller at the end of application launch

解决方案:必须要套一个UINavigationController:,然后把设置window的rootViewController是UINavigationController:

``` 

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];//设置窗口

    ViewController *mvc = [[ViewController alloc] init];

``` 

//注意看这里:

    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:mvc];

    nav.navigationBarHidden = YES;//是否隐藏导航栏

    self.window.rootViewController = nav;//进入的首个页面

    [self.window makeKeyAndVisible];//显示

Demo地址:https://github.com/zhangkang317/YYTextView-Demon

微博的实现原理:服务端根据用户发布的微博内容, 正则匹配出需要@的用户的名字列表,然后根据名字去查用户的ID

我的实现原理:如果按照微博的实现方式,会对我们后台的服务压力比较大,所以自己想了一下就参考了邮箱的方式实现,用户编写内容时,通过选择的方式添加@用户,并以图片的方式展示@用户,同时把用户的信息带上,在发布的时候遍历文本内容,取出图片对象的用户信息,做下简单的数据处理,然后返回给服务端。一下是我的代码具体实现方式。

1、创建YYTextView,

   - (YYTextView *)textView {

        if(_textView ==nil) {

            _textView = [[YYTextView alloc] initWithFrame:CGRectMake(10,10, UI_SCREEN_WIDTH -20,90)];

            _textView.textColor = [UIColor blackColor];

            _textView.font = [UIFont systemFontOfSize:15*SP_SCREEN];

            _textView.scrollEnabled =NO;

            _textView.textParser = [[LPPZSendContentTextParser alloc] init];

            _textView.delegate =self;

            _textView.inputAccessoryView = [UIView new];

            @weakify(self);

        }

        return_textView;

    }

2、将选择的用户数据拼接到文本的内容


  vc.didSelectUserBlock =^(SnsUser*user) {

        @strongify(self);

        [self.textView deleteBackward];

        //将用户的名字user.nickName,用户的ID(user.id)以特定的格式传给内容,方便后面的内容匹配,传入的格式例如:[@张三 -86634993]:

重点:‘-’前面一定要接一个空格,方便后面发布成功后查看文章时将@用户格式区别开来

        [self.textView replaceRange:self.textView.selectedTextRange

                         withText:[NSStringstringWithFormat:@"[@%@ -%@]",user.nickName,user.id]];

    };}


3、每当YYText调用- (void)replaceRange:(UITextRange*)range withText:(NSString*)text;都会调用这个方法LPPZSendContentTextParser这个类的方式

- (BOOL)parseText:(NSMutableAttributedString*)text selectedRange:(NSRangePointer)selectedRange ;在这个方法里我们会对文本的内容做处理

- (BOOL)parseText:(NSMutableAttributedString*)text selectedRange:(NSRangePointer)selectedRange {


    {

        //1、正则匹配出符合[@张三 -86634993]这种格式的内容,正则表达式为(\\[[^\\]]*\\])

        NSArray *emoticonResults = [[LPPZHelper regex_MoodAtUser] matchesInString:text.string options:kNilOptions range:text.yy_rangeOfAll];

        NSUIntegerclipLength =0;

        for(NSTextCheckingResult*emoinemoticonResults) {

            if(emo.range.location==NSNotFound&& emo.range.length<=1)continue;

            NSRangerange = emo.range;

            range.location-= clipLength;

            if([textyy_attribute:YYTextAttachmentAttributeName atIndex:range.location])continue;


            //2.根据range取出[@张三 -86634993]

            NSMutableString *tmp1 = [NSMutableString stringWithString: [text.string substringWithRange:range]];

            //3、去掉头部和尾部的中括号[],得到@张三 -86634993

            NSMutableString *tmp2 = [NSMutableString stringWithString: [tmp1 stringByReplacingOccurrencesOfString:@"[" withString:@""]];

            NSMutableString *tmp3 = [NSMutableString stringWithString: [tmp2 stringByReplacingOccurrencesOfString:@"]" withString:@""]];


            //4.得到"@张三 "(不包含双引号)

            NSString *emoString = [tmp3 componentsSeparatedByString:@"-"].firstObject;

            //4.得到用户Id"86634993"(不包含双引号)

            NSString *userId = [tmp3 componentsSeparatedByString:@"-"].lastObject;


            //5、做一些异常数据的场景处理

            if(![tmp1hasPrefix:@"[@"]) {

                continue;

            }

            if ([tmp3 componentsSeparatedByString:@"-"].count !=2) {

                continue;

            }

            if(NULLString(userId)) {

                continue;

            }

            //6、根据"@张三 "(不包含双引号)生成一个对象LPPZLabelImage

            LPPZLabelImage * image = [LPPZLabelImage imageWithText:emoString

                                                              font:_atUserFont

                                                         textColor:HEXRGBCOLOR(0x0068b7)

                                                   backgroundColor:[UIColor whiteColor]];

            if(!image.image)continue;

            __blockBOOLcontainsBindingRange =NO;

            [text enumerateAttribute:YYTextBindingAttributeName

                             inRange:range

                             options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired

                          usingBlock:^(idvalue, NSRange range,BOOL*stop) {

                              if(value) {

                                  containsBindingRange =YES;

                                  *stop =YES;

                              }

                          }];

            if(containsBindingRange)continue;


            YYTextBackedString *backed = [YYTextBackedString stringWithString:emoString];

            NSMutableAttributedString*atr = [[NSMutableAttributedString alloc] initWithString:YYTextAttachmentToken];

            YYTextAttachment *attach = [YYTextAttachment new];

            //7、LPPZLabelImage的image赋值给YYTextAttachment

            attach.content = image.image;

            attach.contentMode = UIViewContentModeScaleAspectFit;

            //8、YYTextAttachment对象包含了用户昵称和用户Id

            attach.userInfo =@{kLPPZLinkATUserID:userId ,kLPPZLinkATUserName :emoString};

            [atr yy_setTextAttachment:attach range:NSMakeRange(0, atr.length)];



            //9.设置YYTextAttachment的大小以及位置

            YYTextRunDelegate *delegate = [YYTextRunDelegate new];

            delegate.width = image.lppz_TextSize.width;

            CGFloatfontHeight = _font.ascender - _font.descender;

            CGFloatyOffset = _font.ascender - fontHeight *0.5;

            delegate.ascent = image.lppz_TextSize.height *0.5+ yOffset;

            delegate.descent = image.lppz_TextSize.height - delegate.ascent;

            if(delegate.descent <0) {

                delegate.descent =0;

                delegate.ascent = image.lppz_TextSize.height;

            }


            CTRunDelegateRef delegateRef = delegate.CTRunDelegate;

            [atr yy_setRunDelegate:delegateRef range:NSMakeRange(0, atr.length)];

            if(delegate) CFRelease(delegateRef);

            //10,此时图片富文本对应的字符串内容是"@张三 "(不包含双引号) ,(传给服务端的内容是字符串而不是富文本)

            [atr yy_setTextBackedString:backed range:NSMakeRange(0, atr.length)];

            [atr yy_setTextBinding:[YYTextBinding bindingWithDeleteConfirm:NO] range:NSMakeRange(0, atr.length)];

            //11.textView原来位置的内容是[@张三 -86634993] 现在替换成了YYTextAttachment(图片富文本)

            [textreplaceCharactersInRange:range withAttributedString:atr];


            if(selectedRange) {

                *selectedRange = [self_replaceTextInRange:range withLength:atr.length selectedRange:*selectedRange];

            }

            clipLength += range.length- atr.length;

        }

    }


    return YES;

}

然后这个时候YYtextView展示的内容不是text 而是富文本NSMutableAttributedString

4、用户点击提交的时候对文本内容我们将遍历内容

//在第三步,我们放的是YYTextAttachment对象,遍历的时候会取出这部分内容,而这部分内容是@用户的图片富文本,

        [self.textView.attributedText enumerateAttribute:YYTextAttachmentAttributeName

                                                 inRange:NSMakeRange(0,self.textView.attributedText.string.length)

                                                 options:0

                                              usingBlock:^(idvalue,NSRangerange,BOOL*stop) {

                                                  if([valueisKindOfClass: [YYTextAttachmentclass]]) {

                                                      YYTextAttachment* attachMent = (YYTextAttachment*)value;

                                        //取出的图片富文本中包含了之前存进入的 用户数据                                                                                                               if(attachMent.userInfo!=nil) {

                                                          [self.viewModeladdAtUserInfo:attachMent.userInfo];

                                                      }

                                                  }

                                              }];

遍历完毕取出需要的用户数据后,就可以单独发送给服务端,

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容