2015-05-20 131 views
1

我正在开发一个应用程序,让用户通过输入@用户名来提及其他用户。虽然我有found a way来检测@字符,并在文本字符串中突出显示选定的用户名,但我不确定如何在用户提到用户时管理事件,但想要从提及中删除该用户。如何删除NSAttributedString的整个块

例如,在Facebook应用程序中,当您提到某人时,UITextView中的该人员姓名将以浅蓝色背景突出显示。但是,当您开始删除提及时,删除属性字符串中的最后一个字符时,整个提及将被删除。

因此,我正在寻找一种方法,当用户删除属性字符串的最后一个字符以删除整个属性字符串并从文本视图中完全删除提及时,我可以捕获该方法。

+0

如何子类化NSAttributedString'并添加额外的属性来捕获字符串包含用户名的事实? –

回答

1

如果您已将整个@username包围在属性UITextView中并覆盖-deleteBackward以检查游标是否位于其中一个用户名属性中。如果不是,只需调用超级实现,否则找到起始位置和用户名的长度并删除整个范围。

+0

这看起来像一个明智的方法给我。我正在研究利用NSTextStorage,但看起来像这样会不必要的复杂。 –

+0

@路易斯你有没有得到它的工作? –

+0

我采取了不同的方法,但您指出了正确的方向。当我回家时我会分享一些代码。 –

3

为了达到上述所需的行为,我最终做了以下工作。我将所有这些方法实现为放置UITextView的视图控制器的一部分,因此我在视图控制器中添加了UITextViewDelegate协议。然后,我采取了以下方法:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{ 
    //if this is true, then the user just deleted a character by using backspace 
    if(range.length == 1 && text.length == 0){    
     NSUInteger cursorPosition = range.location; //gets cursor current position in the text 
     NSRange attrRange; //will store the range of the text that holds specific attributes 
     NSDictionary *attrs = [_content.attributedText attributesAtIndex:cursorPosition effectiveRange:&attrRange]; 

     //check if the attributes of the attributed text in the cursor's current position correspond to what you want to delete as a block 
     if([attrs objectForKey:NSBackgroundColorAttributeName]){ 
      NSAttributedString *newStr = [_content.attributedText attributedSubstringFromRange:NSMakeRange(0, attrRange.location)]; //creates a new NSAttributed string without the block of text you wanted to delete 
      _content.attributedText = newStr; //substitute the attributed text of your UITextView 
      return NO; 
     } 
    } 
    return YES; 
} 
0

路易斯·德尔加多的出色答卷给了我很大的起跳点,但有几个缺点:

  • 总是清除该字符串的结尾
  • 不处理插入令牌
  • 不处理修改包括令牌的选定文本

这里是我的版本(SWIFT 4):

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { 

    if range.location < textView.attributedText.length { 

     var shouldReplace = false 
     var tokenAttrRange = NSRange() 
     var currentReplacementRange = range 
     let tokenAttr = NSAttributedStringKey.foregroundColor 

     if range.length == 0 { 
      if nil != textView.attributedText.attribute(tokenAttr, at: range.location, effectiveRange: &tokenAttrRange) { 
       currentReplacementRange = NSUnionRange(currentReplacementRange, tokenAttrRange) 
       shouldReplace = true 
      } 
     } else { 
      // search the range for any instances of the desired text attribute 
      textView.attributedText.enumerateAttribute(tokenAttr, in: range, options: .longestEffectiveRangeNotRequired, using: { (value, attrRange, stop) in 
       // get the attribute's full range and merge it with the original 
       if nil != textView.attributedText.attribute(tokenAttr, at: attrRange.location, effectiveRange: &tokenAttrRange) { 
        currentReplacementRange = NSUnionRange(currentReplacementRange, tokenAttrRange) 
        shouldReplace = true 
       } 
      }) 
     } 

     if shouldReplace { 
      // remove the token attr, and then replace the characters with the input str (which can be empty on a backspace) 
      let mutableAttributedText = textView.attributedText.mutableCopy() as! NSMutableAttributedString 
      mutableAttributedText.removeAttribute(tokenAttr, range: currentReplacementRange) 
      mutableAttributedText.replaceCharacters(in: currentReplacementRange, with: text) 
      textView.attributedText = mutableAttributedText 

      // set the cursor position to the end of the edited location 
      if let cursorPosition = textView.position(from: textView.beginningOfDocument, offset: currentReplacementRange.location + text.lengthOfBytes(using: .utf8)) { 
       textView.selectedTextRange = textView.textRange(from: cursorPosition, to: cursorPosition) 
      } 

      return false 
     } 
    } 

    return true 
} 

如果你需要重写一个超类,加上override关键字和,而不是在最后返回true,则返回

super.textView(textView, shouldChangeTextIn: range, replacementText: text)

你可以将tokenAttr更改为任何标准或自定义文本属性。如果将enumerateAttribute更改为enumerateAttributes,则甚至可以查找文本属性的组合。