我正在开发一款应用,可让用户输入@ 用户名来提及其他用户。虽然我有found a way来检测@字符并在文本字符串中突出显示所选用户名,但我不确定如何在用户提及用户但又希望从提及中删除该用户时管理该事件。 / p>
例如,在Facebook应用中,当您提及某人时,UITextView中该人物的名称会以浅蓝色背景突出显示。但是,当您开始删除该提及时,当您删除属性字符串中的最后一个字符时,整个提及将被删除。
因此,我正在寻找一种方法,当用户删除属性字符串的最后一个字符时,我可以捕获该方法,以便删除整个属性字符串并从文本视图中完全删除提及。
答案 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;
}
答案 1 :(得分:1)
如果您已经将整个@username
包围了属性,子类UITextView
并覆盖-deleteBackward
以检查游标是否位于其中一个用户名属性中。如果没有,只需调用超级实现,否则找到起始位置和属性用户名的长度并删除整个范围。
答案 2 :(得分:1)
这是我的版本(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,您甚至可以查找文本属性的组合。