【发布时间】:2018-05-18 20:12:54
【问题描述】:
我有一个 UITextView,有时我需要以全部大写形式显示,有时以原始情况显示。这部分很简单,但是当用户开始编辑文本时,我需要使用更改更新原始字符串,同时保留字符串的原始大小写。出于这个原因,我无法使用 textDidChange 而是使用 shouldChangeTextIn 并更改原始字符串。大多数情况下,一切都按预期工作,除非选择了多个单词并且您在键盘上点击预测词。可能还有其他事情会破坏。解决此问题以在显示变异字符串的同时保留原始字符串的最佳方法是什么。这是一个最小的例子。
import UIKit
class ViewController: UIViewController {
lazy var textView : UITextView = {
let txtv = UITextView(frame: CGRect(x: 0, y:40, width: self.view.frame.width, height: 200))
txtv.autoresizingMask = [.flexibleWidth,.flexibleHeight]
txtv.delegate = self
txtv.font = UIFont.systemFont(ofSize: 22)
return txtv
}()
lazy var button : UIButton = {
let btn = UIButton(frame: CGRect(x: 0, y:250, width: self.view.frame.width - 40, height: 50))
btn.autoresizingMask = [.flexibleWidth,.flexibleHeight]
btn.setTitleColor(UIColor.blue, for: .normal)
btn.setTitle("SHOW TEXT", for: .normal)
btn.addTarget(self, action: #selector(changeState), for: .touchUpInside)
return btn
}()
var textString = "This is a test to see how we are doing"
var shouldCapitalize : Bool = true
private var hack_shouldIgnorePredictiveInput = false
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(textView)
self.view.addSubview(button)
//get things going
updateTextView()
}
func updateTextView(){
//we could change font size here or size of textview
var textToShow = self.textString
if shouldCapitalize == true{
textToShow = textToShow.uppercased()
}
textView.text = textToShow
print("the text string we really care about is::::: \(textString)")
}
@objc func changeState(){
shouldCapitalize = !shouldCapitalize
updateTextView()
}
}
extension ViewController : UITextViewDelegate{
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if hack_shouldIgnorePredictiveInput {
hack_shouldIgnorePredictiveInput = false
return false
}
hack_shouldIgnorePredictiveInput = true
//how do i replace the characters or text changging without changing the case of the original string
print("the textview text is \(textView.text)")
print("the textview text is \((textView.text as NSString).length)")
print("the range is \(range)")
print("the text is \(text)")
let selectedRange = self.textView.selectedRange
if let str = textView.text as? NSString{
if range.length == 0 && text == ""{
print("the ext is empty")
textString = ""
updateTextView()
}
if let tracker = textString as? NSString{
if range.location == tracker.length{
print("adding")
print("the lenght of the tracker is \(tracker.length)")
let newRange = NSMakeRange(tracker.length, range.length)
print("the new range is \(newRange)")
let newString = tracker.replacingCharacters(in: newRange, with: text)
print("the new text is \(newString)")
textString = newString
updateTextView()
}else if range.location < tracker.length{
let newString = tracker.replacingCharacters(in: range, with: text)
print("the new text is \(newString)")
textString = newString
updateTextView()
if (newString as NSString).length > tracker.length{
print("setting cursor \(NSMakeRange(range.location + range.length, 0))")
self.textView.selectedRange = NSMakeRange(range.location + range.length + 1, 0)
}else{
self.textView.selectedRange = NSMakeRange(range.location, 0)
}
}else{
//the problem seems to be in here
print("maybe adding")
print("the lenght of the tracker is \(tracker.length)")
let newRange = NSMakeRange(tracker.length, range.length)
print("the new range is \(newRange)")
let newString = str.replacingCharacters(in: newRange, with: text)
print("the new text is \(newString)")
textString = newString
updateTextView()
}
}
}
hack_shouldIgnorePredictiveInput = false
return false
}
}
【问题讨论】:
-
您最后的 else 语句的注释为
//the problem seems to be in here。只有range.location大于tracker.length因为其他if...else已经捕获了其他情况,您才会进入其他情况。似乎让range.location大于tracker.length的唯一方法是将textString = ""设置在您检查range.length == 0 && text == ""的上方。我不太明白这一切。也许您可以提供打印语句的输出以获得更多上下文。为每个打印语句提供唯一的文本以避免歧义。 -
@jimmyg 你帮我指出我的最后一个 else 不应该是必要的,当我写它时我认为它是不需要的。它被调用的原因是 textview 试图添加一个带有预测文本的空格,我拦截了它并将字符串设置为空,这使得最后一个 else 被命中。我想我现在明白了,但感谢你触发了我的直觉。