代码之家  ›  专栏  ›  技术社区  ›  Ivan Cantarino

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

  •  5
  • Ivan Cantarino  · 技术社区  · 7 年前

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

    将应用拖放(主要是拖放)的主屏幕之一位于 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 在mail应用程序中,当您将项目或图像拖动到其中时,它会显示一个跟踪光标,以便您知道放置内容的位置,但在我的示例中我无法做到这一点。

    如果我想下降到一个特定的位置,我必须先把光标放在所需的位置,然后执行下降,所以在 performDrop 如您所见,我通过 selectedRange .

    我想在拖放动画发生时看到光标流,就像mail应用程序或notes应用程序一样,在那里你可以选择拖放对象的位置。

    有人对如何实现这一点有什么建议吗?

    2 回复  |  直到 7 年前
        1
  •  2
  •   Maurice    7 年前

    您可以通过设置 selectedRange 到a NSRange 有效位置和长度为 0 .

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

    1. 计算触摸在superview中的当前位置,例如,您可以使用 touchesMoved: ,然后将触摸的位置转换为textView的坐标系

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

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

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

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

        2
  •  2
  •   Maurice Parker    4 年前

    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
    }