如何防止用户在 Swift 5 中的 UITextView 中添加太多换行符?
How can I prevent a user from adding too many line breaks in a UITextView in Swift 5?
我有一个 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
}
}
没有抛出任何错误消息,因为代码完全按照我的要求执行,但我显然以错误的方式提出要求。
我能做什么?
你所描述的逻辑正在发生,因为你总是递增计数器,但从不递减它。你 应该 递减计数器,如果你递增计数器,但最终没有将新行添加到 TextView
。
...
present(newlineAC, animated: true)
characterCounter-=1
return false
...
为什么要减:
通过在这个函数中returning 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
}
}
确保如果用户删除,该函数将 return 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
}
}
这是我的解决方案:
更新 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
开始
我有一个 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
}
}
没有抛出任何错误消息,因为代码完全按照我的要求执行,但我显然以错误的方式提出要求。 我能做什么?
你所描述的逻辑正在发生,因为你总是递增计数器,但从不递减它。你 应该 递减计数器,如果你递增计数器,但最终没有将新行添加到 TextView
。
...
present(newlineAC, animated: true)
characterCounter-=1
return false
...
为什么要减:
通过在这个函数中returning 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
}
}
确保如果用户删除,该函数将 return 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
}
}
这是我的解决方案:
更新 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