在 UITextView 中拖放时显示文本光标
Show text cursor on drag and drop in UITextView
我正在我的应用程序中实现拖放功能。
应用拖放(主要是拖放)的主屏幕之一位于 UITextView
。
我已使用以下代码为此 UITextView
添加了放置交互:
let dropInteraction = UIDropInteraction(delegate: self)
inputTextView.addInteraction(dropInteraction)
通过这样做,我现在接受掉落。
为了仅接受图像和文本作为放置,我实现了以下委托方法:
func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
return session.hasItemsConforming(toTypeIdentifiers: [kUTTypeImage as String, kUTTypeText as String]) && session.items.count == 1
}
根据需要,我还实现了以下必需的委托方法 return a UIDropProposal
:
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
let dropProposal: UIDropProposal = UIDropProposal(operation: .copy)
dropProposal.isPrecise = true
return dropProposal
}
然后在 performDrop 委托方法中我处理丢弃的内容并将其附加到 UITextView
func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
// Access the dropped object types: UIImage, NSString
session.loadObjects(ofClass: UIImage.self) { (imageItems) in
let images = imageItems as! [UIImage]
guard var image = images.first else { return }
// scale the image
image = UIImage(cgImage: image.cgImage!, scale: 4, orientation: .up)
let currentText: NSMutableAttributedString = NSMutableAttributedString(attributedString: self.inputTextView.attributedText)
let textAttachment = NSTextAttachment()
textAttachment.image = image
let imageText = NSAttributedString(attachment: textAttachment).mutableCopy() as! NSMutableAttributedString
let imageStyle = NSMutableParagraphStyle()
imageStyle.alignment = .center
imageText.addAttribute(NSAttributedStringKey.paragraphStyle, value: imageStyle, range: NSMakeRange(0, imageText.length))
// Prepares the string to append with line breaks and the image centered
let attributedStringToAppend: NSMutableAttributedString = NSMutableAttributedString(attributedString: NSAttributedString(string: "\n\n"))
attributedStringToAppend.append(imageText)
attributedStringToAppend.append(NSAttributedString(string: "\n\n"))
// Applies text attributes to the NSMutableAttrString as the default text input attributes
let range: NSRange = NSRange.init(location: 0, length: attributedStringToAppend.length)
let style = NSMutableParagraphStyle()
style.lineSpacing = 4
style.alignment = .center
let font = Font(.installed(.OpenSansRegular), size: .custom(18)).instance
let attr: [NSAttributedStringKey : Any] = [NSAttributedStringKey(rawValue: NSAttributedStringKey.paragraphStyle.rawValue): style, NSAttributedStringKey(rawValue: NSAttributedStringKey.font.rawValue): font, NSAttributedStringKey(rawValue: NSAttributedStringKey.foregroundColor.rawValue): UIColor.rgb(red: 52, green: 52, blue: 52)]
attributedStringToAppend.addAttributes(attr, range: range)
let location = self.inputTextView.selectedRange.location
currentText.insert(attributedStringToAppend, at: location)
self.inputTextView.attributedText = currentText
}
session.loadObjects(ofClass: NSString.self) { (stringItems) in
let strings = stringItems as! [NSString]
guard let text = strings.first else { return }
self.inputTextView.insertText(text as String)
}
}
通过执行所有这些操作,图像和文本都按预期放入了所需的字段中,但我这里有一个问题。
在邮件应用程序的 New Mail Composer
中,当您将项目或图像拖到其中时,它会显示一个跟踪光标,以便您知道放置内容的位置,但我无法在我的例子。
滴到现有文本的末尾。
如果我想放置到特定位置,我必须先将光标放在所需位置然后执行放置,因此在 performDrop
函数中如您所见,我检索光标位置通过 selectedRange
.
我想看到光标在放置动画时流动,就像邮件应用程序或笔记应用程序一样,您可以在其中选择放置对象的位置。
有人知道如何实现吗?
提前致谢。
您可以通过将 selectedRange
设置为具有有效位置和长度 0
的 NSRange
来在 textView 或 textField 中移动光标。
我不会用完成的代码来破坏你,而是一步一步地解释如何自己解决问题:
计算触摸在superview中的当前位置,例如你可以使用touchesMoved:
,然后将触摸的位置转换为textView的坐标系
通过应用 textView 的文本属性(字体、大小等)来计算 textView 的边界矩形 text
,如下所示:
[textView.text boundingRectWithSize:textView.bounds.size options:NSStringDrawingUsesLineFragmentOrigin attributes:textAttributesDict context:nil]
将触摸位置与文本的边界矩形匹配,并在文本中找到所需的位置
将textView.selectedRange
设置为NSMakeRange(calculatedLoc, 0)
我发现最简单的方法是更新 sessionDidUpdate
中的光标。
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
inputTextView.becomeFirstResponder()
let point = session.location(in: textView)
if let position = inputTextView.closestPosition(to: point) {
inputTextView.selectedTextRange = inputTextView.textRange(from: position, to: position)
}
let dropProposal: UIDropProposal = UIDropProposal(operation: .copy)
dropProposal.isPrecise = true
return dropProposal
}
我正在我的应用程序中实现拖放功能。
应用拖放(主要是拖放)的主屏幕之一位于 UITextView
。
我已使用以下代码为此 UITextView
添加了放置交互:
let dropInteraction = UIDropInteraction(delegate: self)
inputTextView.addInteraction(dropInteraction)
通过这样做,我现在接受掉落。
为了仅接受图像和文本作为放置,我实现了以下委托方法:
func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
return session.hasItemsConforming(toTypeIdentifiers: [kUTTypeImage as String, kUTTypeText as String]) && session.items.count == 1
}
根据需要,我还实现了以下必需的委托方法 return a UIDropProposal
:
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
let dropProposal: UIDropProposal = UIDropProposal(operation: .copy)
dropProposal.isPrecise = true
return dropProposal
}
然后在 performDrop 委托方法中我处理丢弃的内容并将其附加到 UITextView
func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
// Access the dropped object types: UIImage, NSString
session.loadObjects(ofClass: UIImage.self) { (imageItems) in
let images = imageItems as! [UIImage]
guard var image = images.first else { return }
// scale the image
image = UIImage(cgImage: image.cgImage!, scale: 4, orientation: .up)
let currentText: NSMutableAttributedString = NSMutableAttributedString(attributedString: self.inputTextView.attributedText)
let textAttachment = NSTextAttachment()
textAttachment.image = image
let imageText = NSAttributedString(attachment: textAttachment).mutableCopy() as! NSMutableAttributedString
let imageStyle = NSMutableParagraphStyle()
imageStyle.alignment = .center
imageText.addAttribute(NSAttributedStringKey.paragraphStyle, value: imageStyle, range: NSMakeRange(0, imageText.length))
// Prepares the string to append with line breaks and the image centered
let attributedStringToAppend: NSMutableAttributedString = NSMutableAttributedString(attributedString: NSAttributedString(string: "\n\n"))
attributedStringToAppend.append(imageText)
attributedStringToAppend.append(NSAttributedString(string: "\n\n"))
// Applies text attributes to the NSMutableAttrString as the default text input attributes
let range: NSRange = NSRange.init(location: 0, length: attributedStringToAppend.length)
let style = NSMutableParagraphStyle()
style.lineSpacing = 4
style.alignment = .center
let font = Font(.installed(.OpenSansRegular), size: .custom(18)).instance
let attr: [NSAttributedStringKey : Any] = [NSAttributedStringKey(rawValue: NSAttributedStringKey.paragraphStyle.rawValue): style, NSAttributedStringKey(rawValue: NSAttributedStringKey.font.rawValue): font, NSAttributedStringKey(rawValue: NSAttributedStringKey.foregroundColor.rawValue): UIColor.rgb(red: 52, green: 52, blue: 52)]
attributedStringToAppend.addAttributes(attr, range: range)
let location = self.inputTextView.selectedRange.location
currentText.insert(attributedStringToAppend, at: location)
self.inputTextView.attributedText = currentText
}
session.loadObjects(ofClass: NSString.self) { (stringItems) in
let strings = stringItems as! [NSString]
guard let text = strings.first else { return }
self.inputTextView.insertText(text as String)
}
}
通过执行所有这些操作,图像和文本都按预期放入了所需的字段中,但我这里有一个问题。
在邮件应用程序的 New Mail Composer
中,当您将项目或图像拖到其中时,它会显示一个跟踪光标,以便您知道放置内容的位置,但我无法在我的例子。
滴到现有文本的末尾。
如果我想放置到特定位置,我必须先将光标放在所需位置然后执行放置,因此在 performDrop
函数中如您所见,我检索光标位置通过 selectedRange
.
我想看到光标在放置动画时流动,就像邮件应用程序或笔记应用程序一样,您可以在其中选择放置对象的位置。
有人知道如何实现吗?
提前致谢。
您可以通过将 selectedRange
设置为具有有效位置和长度 0
的 NSRange
来在 textView 或 textField 中移动光标。
我不会用完成的代码来破坏你,而是一步一步地解释如何自己解决问题:
计算触摸在superview中的当前位置,例如你可以使用
touchesMoved:
,然后将触摸的位置转换为textView的坐标系通过应用 textView 的文本属性(字体、大小等)来计算 textView 的边界矩形
text
,如下所示:[textView.text boundingRectWithSize:textView.bounds.size options:NSStringDrawingUsesLineFragmentOrigin attributes:textAttributesDict context:nil]
将触摸位置与文本的边界矩形匹配,并在文本中找到所需的位置
将
textView.selectedRange
设置为NSMakeRange(calculatedLoc, 0)
我发现最简单的方法是更新 sessionDidUpdate
中的光标。
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
inputTextView.becomeFirstResponder()
let point = session.location(in: textView)
if let position = inputTextView.closestPosition(to: point) {
inputTextView.selectedTextRange = inputTextView.textRange(from: position, to: position)
}
let dropProposal: UIDropProposal = UIDropProposal(operation: .copy)
dropProposal.isPrecise = true
return dropProposal
}