关于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];

                                                      }

                                                  }

                                              }];

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

你可能感兴趣的:(关于YYTextView的一些想法)