PKCanvasView no longer shows edit (paste) menu on long press (iOS 16.1)

You used to be able to select a drawing, long press to show the edit menu (copy, duplicate, delete, ...), copy the item and paste it after another long press on the canvas. However, since iOS / iPadOS 16.1 long pressing the canvas does not show any menu. The action still works if you connect an external mouse to your iPad, activate the secondary click functionality and use the right mouse button to click on the canvas. This shows the menu and you can paste the copied drawing. It seems to be broken in all PencilKit-based apps, including Apple's sample apps. Is there any workaround? This is a major problem for my app and used to work fine since the introduction of PencilKit with iOS 13.

Post not yet marked as solved Up vote post of mbuchetics Down vote post of mbuchetics
2k views

Replies

I believe you can / have to use UIEditMenuInteraction to implement your own edit menu now. The original default menu still shows up in Notes, but in Freeform it’s a different one, so I guess Apple has decided that a single set of edit actions do not suit all PencilKit based apps, and therefore the original menu is no long the default.

  • Thanks @Alan_Z, that works! I implemented it as described in https://developer.apple.com/documentation/uikit/uieditmenuinteraction - however, the content is now always pasted in the center of the canvas. Previously it was inserted at approximately at the long press touch location. Any idea how I can customize the insert location of the pasted content?

  • @mbuchetics you're welcome! Please see my reply below since I can't post code blocks here. Btw, could you share your app's name?

  • @mbuchetics you're welcome! Please see my reply below since I can't post code blocks here. Btw, could you share your app's name?

Add a Comment

@mbuchetics you're welcome! To my knowledge, in order to paste at the right location, you have to implement your own paste function, by subclassing the PKCanvasView and overriding paste(:_). In this override you have to modify the underlying PKDrawing yourself, roughly like so:

/// Edit menu location, set by whatever method you use to trigger the edit menu.
var editMenuLocation: CGPoint = .zero
    
/// Pasting at `editMenuLocation`.
override func paste(_ sender: Any?) {
    guard let data = UIPasteboard.general.data(forPasteboardType: "com.apple.drawing"),
          let drawing = try? PKDrawing(data: data)
    else { return }
    
    let center = CGPoint(x: drawing.bounds.midX, y: drawing.bounds.midY)
    let target = editMenuLocation / zoomScale // I have some CGPoint extensions dealing with arithmetic
    let offset = target - center
    let withOffset = drawing.transformed(using: .init(translationX: offset.x, y: offset.y))
    let strokes = withOffset.strokes
    self.drawing.strokes.append(contentsOf: strokes)
}

The problem is that by modifying the PKDrawing directly you confuses the default UndoManager, and therefore may have to implement your own undo stack. I'm still developing my first (and likely only) PencilKit app and haven't really got to the undo/redo stage, so my knowledge here is limited.

@Alan_Z thank you for posting this solution! I've been trying to figure out what happened with PKCanvasView's edit menu and your answer is the only mention of what happened I've seen on the internet! Sometimes it is truly hard to understand how Apple can make such a drastic change to one of their libraries and make no mention of it at all.

I've managed to get your solution running, and now I am facing the same issue you've mentioned, namely having to modify the paste method, for among other things, setting in which location of the canvas to paste.

I was wondering if you've managed to find an elegant solution to this that correctly updates the undo manager, and if so if it would be possible for you to share it.

Again, thank you. You've already been exceedingly helpful by virtue of your above answer alone.

I still can't find this mentioned anywhere else, but one of my customers discovered that if you use 3 fingers to tap instead of long-pressing one finger, you get an edit menu at the top of the page, with Paste as an option. I've logged a bug with Apple, but they haven't responded and it's been about two months.

@joaqo thanks for the kind words, it's nice to meet a fellow sufferer :)

I ended up implementing my own undo stack. I needed it anyway since I had to support pasting images etc. I asked an engineer in a WWDC lab this year, and he said (basically, my interpretation, not his exact words) that this was the intended way of doing this. I haven't been working on this for quite some time, and I remember I had some issues with the undo stack using this method in some rare cases. But now when I try to find where it breaks, I can't really find any (should have documented them..).

How did you solve this in the end? If you see problems about the undo stack, could you share with me so I can check again in my code?

  • I ended up implementing my own undo stack as well, which was fine as I ended up using it extensively on my app.

Add a Comment

Heads up @Alan_Z , we're now at iOS17 and Apple has reintroduced the default tap on canvas to open the default edit menu behaviour mentioned in this post. Of course this has broken my app again 😂. Thanks Apple I guess.

I had created my own edit menu after apple disabled the default pencil kit one originally mentioned in this post. I just realized that them re-enabling it in iOS17 is collliding with the custom one I had created and I am seeing no way of making them play well together. In the off chance that you're going through the same thing @Alan_Z , would you happen to know how to add some items to pkcanvasview's edit menu?

  • Have you found a solution for this, I have the same problem?

Add a Comment