我有一个UITextView
,可让用户输入他们刚刚录制的某些音频文件的注释。
我想将它们可以使用的“ \ n”(换行符)的数量限制为5(即,注释的长度最多为5行)。
如果他们尝试转到第六行,我想显示一条带有有意义消息的警报,并且在相对操作中按“确定”按钮时,我希望用户可以编辑其文本。
已经建立了授权,现在我正在执行optional func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool
。
我放入的逻辑正确显示了警报,但是,在单击“确定”并尝试删除一些字符后,再次调用该方法,我得到了警报。
我知道这是由于计数器仍停留在5,但将其重置为0则允许9行或更多,所以这不是解决方案。
这是我尝试过的代码,无法正常工作:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == characterToCheck /* \n, declared globally */ {
characterCounter += 1 // this was also declared as a global property
}
if characterCounter > 4 {
let newlineAC = UIAlertController(title: "Too many linebreaks", message: "Please go back and make your comment fit into a maximum of 5 lines", preferredStyle: .alert)
newlineAC.addAction(UIAlertAction(title: "OK", style: .default) { [weak self] (_) in
let currentText = textView.text ?? ""
guard let currentTextRange = Range(range, in: currentText) else { return }
self?.comments.text = currentText.replacingOccurrences(of: "\n", with: "@ ", range: currentTextRange)
})
present(newlineAC, animated: true)
return false
} else {
return true
}
}
不会抛出任何错误消息,因为代码完全符合我的要求,但是我显然以错误的方式提出了要求。 我该怎么办?
答案 0 :(得分:1)
这是我的解决方法:
更新了 Matt Bart 反馈
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == String(characterToCheck) /* \n, declared globally */ {
characterCounter += 1 // this was also declared as a global property
}
if text == "" {
let characters = Array(textView.text)
if characters.count >= range.location {
let deletedCharacter = characters[range.location]
if deletedCharacter == characterToCheck {
characterCounter -= 1
}
}
}
if characterCounter > 4 {
let newlineAC = UIAlertController(title: "Too many linebreaks", message: "Please go back and make your comment fit into a maximum of 5 lines", preferredStyle: .alert)
newlineAC.addAction(UIAlertAction(title: "OK", style: .default) { [weak self] (_) in
let currentText = textView.text ?? ""
guard let currentTextRange = Range(range, in: currentText) else { return }
self?.comments.text = currentText.replacingOccurrences(of: "\n", with: "@ ", range: currentTextRange)
})
present(newlineAC, animated: true, completion: { [weak self] in
self?.characterCounter -= 1
})
return false
} else {
return true
}
}
}
还要将characterToCheck
声明为Character
而不是String
characterCounter
必须从0
答案 1 :(得分:0)
您正在描述的逻辑之所以发生,是因为您始终在增加计数器,但从未减少计数器。如果您增加了计数器,则应该递减计数器,但是永远不要将新行添加到TextView
中。
...
present(newlineAC, animated: true)
characterCounter-=1
return false
...
为什么要递减:
通过在此函数中返回false
,TextView不会将新更改添加到TextView。由于未添加它们,因此不应计入characterCount
。
选择删除
当用户一次删除整个文本选择时,还必须考虑到。
let text = NSString(string: textView.text)
for char in text.substring(with: range) {
print(char)
if char == characterToCheck {
//if the text that is going to be removed has the character
//remove it from the count
characterCounter-=1
}
}
确保用户是否要删除,该函数将返回true
,以便实际删除文本。
粘贴(选择插入)
如果用户粘贴,我们需要检查一堆文本,以确认其中的换行符。
for char in replacementString {
if char == characterToCheck {
characterCounter+=1
}
}
现在在一起
这考虑了所有因素。还使用新变量来更新一点逻辑。
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
var localCount = characterCount
//check for deletion
let NStext = NSString(string: textView.text)
for char in NStext.substring(with: range) {
print(char)
if char == characterToCheck {
//if the text that is going to be removed has the character
//remove it from the count
localCount-=1
}
}
//check for insertion
//this will also replace the simple check in the beginning
for char in replacementString {
if char == characterToCheck {
//if any of the character being inserted is the one
//will be taken into account here
localCount+=1
}
}
if localCount > 4 {
let newlineAC = UIAlertController(title: "Too many linebreaks", message: "Please go back and make your comment fit into a maximum of 5 lines", preferredStyle: .alert)
newlineAC.addAction(UIAlertAction(title: "OK", style: .default) { [weak self] (_) in
let currentText = textView.text ?? ""
guard let currentTextRange = Range(range, in: currentText) else { return }
self?.comments.text = currentText.replacingOccurrences(of: "\n", with: "@ ", range: currentTextRange)
})
present(newlineAC, animated: true)
return false
} else {
characterCounter = localCount
//only updates if has an OK # of newlines
return true
}
}