提问人:smeshko 提问时间:11/18/2023 更新时间:11/21/2023 访问量:60
在 UILabel 中生成的文本后添加自定义视图
Add a custom view following generated text in UILabel
问:
我正在生成文本,想象一下 ChatGPT 如何批量生成文本。我想要一个跟随该文本的自定义视图(如光标/插入符号)。我不介意使用 、 或其他任何东西。UILabel
UITextField
UITextView
我试过使用和以下代码UITextView
override func caretRect(for position: UITextPosition) -> CGRect {
let originalRect = super.caretRect(for: position)
return CGRect(x: originalRect.origin.x, y: -3, width: 18, height: 36)
}
override func draw(_ rect: CGRect) {
super.draw(rect)
let caretRect = self.caretRect(for: self.selectedTextRange?.end ?? self.endOfDocument)
customCursorImage?.draw(in: caretRect)
}
但它的工作并不那么顺利,我不知道如何隐藏系统光标。
我考虑过找到文本末尾并在那里绘制图像,但我找不到任何 API 来做到这一点。CGPoint
寻找任何和所有的想法。
答:
0赞
DonMag
11/21/2023
#1
我们可以使用文本视图来查找当前文本末尾的位置。selectionRects(for:)
这是一个简单的例子......
class ViewController: UIViewController {
let sampleStr: String = "UILabel: \n\nA label can contain an arbitrary amount of text, but UILabel may shrink, wrap, or truncate the text, depending on the size of the bounding rectangle and properties you set. You can control the font, text color, alignment, highlighting, and shadowing of the text in the label."
let theTextView = UITextView()
let fakeCaretView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemYellow
// text view properties
theTextView.isEditable = false
theTextView.font = .systemFont(ofSize: 20.0, weight: .regular)
theTextView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(theTextView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
theTextView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
theTextView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
theTextView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
theTextView.heightAnchor.constraint(equalToConstant: 320.0),
])
// let's add a button
let b1 = UIButton()
b1.setTitle("Do It", for: [])
b1.backgroundColor = .systemBlue
b1.setTitleColor(.white, for: .normal)
b1.setTitleColor(.lightGray, for: .highlighted)
b1.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(b1)
// put the button below the text view
NSLayoutConstraint.activate([
b1.topAnchor.constraint(equalTo: theTextView.bottomAnchor, constant: 20.0),
b1.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
b1.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
])
// actions for button
b1.addTarget(self, action: #selector(doIt(_:)), for: .touchUpInside)
// a "caret / vertical line" view
let lh: CGFloat = theTextView.font?.lineHeight ?? 8.0
fakeCaretView.frame = .init(origin: theTextView.frame.origin, size: .init(width: 4.0, height: lh))
fakeCaretView.backgroundColor = .red
view.addSubview(fakeCaretView)
}
@objc func doIt(_ sender: Any?) {
var activeStrs = sampleStr.components(separatedBy: " ")
// set the text view's text to the first word from the string
var curStr: String = activeStrs.removeFirst()
self.theTextView.text = curStr
// get the "end position" and move the fakeCaretView into place
if let p = self.findPos() {
self.fakeCaretView.frame.origin = .init(x: self.theTextView.frame.origin.x + p.x,
y: self.theTextView.frame.origin.y + p.y)
}
// repeating timer to add words one-by-one to the text view
Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true, block: { t in
if activeStrs.isEmpty {
t.invalidate()
} else {
// get the next word
let s = activeStrs.removeFirst()
// append it to the string
curStr += " " + s
self.theTextView.text = curStr
// get the "end position" and move the fakeCaretView into place
if let p = self.findPos() {
self.fakeCaretView.frame.origin = .init(x: self.theTextView.frame.origin.x + p.x,
y: self.theTextView.frame.origin.y + p.y)
}
}
})
}
func findPos() -> CGPoint? {
// get textRange for entire textView string
guard let r = theTextView.textRange(from: theTextView.beginningOfDocument, to: theTextView.endOfDocument)
else { return nil }
// get the selectionRects
let rects = theTextView.selectionRects(for: r)
// get the last one
guard let lr = rects.last
else { return nil }
return .init(x: lr.rect.maxX, y: lr.rect.minY)
}
}
笔记:
- 我不知道你是想逐个字符、逐个单词、逐串还是逐段......本金是一样的。
- 您需要添加逻辑来处理太长而无法放入文本视图的文本。可能自动滚动它?
- 这只是示例代码!! ...它不打算,也不应该被视为“生产就绪”。
评论