在 UITextView 中拖放时显示文本光标

Posted

技术标签:

【中文标题】在 UITextView 中拖放时显示文本光标【英文标题】:Show text cursor on drag and drop in UITextView 【发布时间】:2018-05-01 04:01:42 【问题描述】:

我正在我的应用中实现拖放。

将应用拖放(主要是拖放)的主要屏幕之一是UITextView

我已使用以下代码向此 UITextView 添加了放置交互:

    let dropInteraction = UIDropInteraction(delegate: self)     
    inputTextView.addInteraction(dropInteraction)

通过这样做,我现在接受其中的掉落。

为了只接受图像和文本作为 drop,我实现了以下委托方法:

func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool 
    return session.hasItemsConforming(toTypeIdentifiers: [kUTTypeImage as String, kUTTypeText as String]) && session.items.count == 1

根据需要,我还实现了以下必需的委托方法来返回 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 函数中,如您所见,我通过@987654331 检索光标位置@。

我想在放置动画发生时看到光标流动,就像邮件应用程序或便笺应用程序一样,您可以在其中选择放置对象的位置。

有人对如何实现这一点有提示吗?

提前致谢。

【问题讨论】:

这个问题你解决了吗? 【参考方案1】:

您可以在 textView 或 textField 中移动光标,方法是将 selectedRange 设置为具有有效位置且长度为 0NSRange

我不会用完成的代码来破坏你,而是逐步解释如何自己解决问题:

    计算当前触摸在superview中的位置,比如你可以使用touchesMoved:,然后将触摸的位置转换成textView的坐标系

    通过应用 textView 的文本属性(字体、大小等)来计算 textView 的 text 的边界矩形,如下所示:

    [textView.text boundingRectWithSize:textView.bounds.size options:NSStringDrawingUsesLineFragmentOrigin attributes:textAttributesDict context:nil]

    将触摸的位置与文本的边界矩形相匹配,并在文本中找到所需的位置

    textView.selectedRange设置为NSMakeRange(calculatedLoc, 0)

【讨论】:

嗯...从来不记得使用 textView 边界矩形!我会尝试你所说的,然后我会回来提供一些反馈 @Ivan Cantarino 你试过了吗?【参考方案2】:

我发现的最简单的方法是更新 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 中拖放时显示文本光标的主要内容,如果未能解决你的问题,请参考以下文章

在没有 MFC 的 Visual Studio 中拖放 UI 设计器?

如何使用 react-dnd 从材质 UI 中拖放 TableHeaderColumn?

在fabric js中擦除iText时显示光标线代替擦除的字符

在 GUI 中拖放

在 C# 托盘中拖放 NotifyIcon

从一个列表中拖放 jQuery UI 可拖动元素并将其放入另一个列表的问题