3

I have an application where I have one custom view which is derived from NSView. Within this view, there are several custom subviews, which are also derived from NSView.

I want to implement a drag and drop behavior which allows URLs to be dropped onto the views. Everything is already working for the main view.

So, actually I would have to implement dragging behavior handlers on the child-views and the parent-view class. The thing is, that I don't want to copy the complete handling code to all the child-views to make them also accept drag events. So I thought that it would be the best way to just let them forward all drag events to the parent view.

Is this possible somehow?? Not sure if I can somehow set this up with the responder-chain maybe?

Any tips are highly appreciated!! Thanks in advance.

guitarflow
  • 2,930
  • 25
  • 38

4 Answers4

7

I faced a similar issue where I wanted anything dropped in a view, or any of it's subviews to be processed by the view, but the calls never got there.

After some research I found this answer to be the most helpful: https://stackoverflow.com/a/7389711/327471

Essentially if a view is not registered to receive any drag events it should pass that information up to it's parent view automatically. So in my case I ended up with something like this:

NSArray *subviews = [self.view subviews];
for (NSView *aSubview in subviews) {
    [aSubview unregisterDraggedTypes];
}

Of course you can be more precise than that, and make sure to only check subclasses of a certain type or whatever parameters you want. But ultimately the key was unregistering the problem subview from it's dragged types.

I hope this helps.

Community
  • 1
  • 1
redbeard
  • 348
  • 4
  • 17
  • This looks exactly as what I need!! Will try it tonight! Your timing is awesome. There were other issues that had to be fixed and I finished the last one yesterday. So I would have asked a new question regarding this exact topic soon. Thanks. Made my day!! – guitarflow Jan 09 '12 at 12:31
  • After trying around I thought it didn't work ... until I found out, that my custom view contains an NSImageView displaying a shading image as an overlay for the complete view. This ate all my drag events. `unregisterDraggedType` solved my issue. Thank you very much!! – guitarflow Jan 09 '12 at 23:17
2

If the subviews are used for display only and don't require any user interaction, you can override -hitTest: in the parent view like so:

- (NSView *)hitTest:(NSPoint)aPoint
{
    NSView* hitView = [super hitTest:aPoint];
    if(hitView)
        return self;
    return nil;
}

This makes the parent view receive all mouse events.

Rob Keniger
  • 45,830
  • 6
  • 101
  • 134
  • Unfortunately, my child views are also receiving mouse-click events. Any other idea? – guitarflow Nov 25 '11 at 09:09
  • You could separately propagate mouse-click events by also overriding mouseUp: in the parent view and propagating that down if it is inside the rect of one of the sub-views. Not very elegant :) – Mark Jan 09 '12 at 03:00
1

Still works XCode 10.1. Swift 4.2. under 10.14.4 Beta (18E184e).

// MARK: - ViewController lifecycle

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.subviews.forEach { $0.unregisterDraggedTypes() }
}
Darkwonder
  • 1,149
  • 1
  • 13
  • 26
-1

There's probably a better way, but you could put your dragging protocol implementation in a category, rather than in the view directly, and include that category in each of the views.

Mark
  • 1,304
  • 12
  • 22