Фон
Реализация по умолчанию NSPopover
будет перемещать всплывающее окно, когда представление отображается поверх прокруток (и имеет специальную обработку для случая, когда NSRect
прикреплено к прокруткам вне поля зрения).NSPopover
может отображаться поверх NSRulerView
, но NSPopover
не перемещается при прокрутке вида документа (очевидно, потому что NSRulerView
не обрабатывает прокрутку, как это делают другие виды, используя смещение чертежа вместодвижущийся видовой экран).
Вопрос
Как воссоздать поведение перемещения по умолчанию для NSPopover
, прикрепленного к NSRulerView
?
Пример кода
ViewController:
@interface ViewController : NSViewController
@property (weak) IBOutlet NSScrollView *scrollView;
@property (strong) LineNumberView *ruler;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.ruler = [[LineNumberView alloc] initWithScrollView:self.scrollView orientation:NSVerticalRuler];
self.scrollView.verticalRulerView = self.ruler;
self.scrollView.hasVerticalRuler = YES;
self.scrollView.rulersVisible = YES;
}
//...
@end
LineNumberView:
@implementation LineNumberView
-(void)mouseDown:(NSEvent *)event {
[self popOver:[self convertPoint:event.locationInWindow fromView:nil]];
}
-(void)popOver:(NSPoint)point {
NSRect anchor = [self rectForPoint:point];
PopoverController *pop = [[PopoverController alloc] init];
[pop showOver:anchor ofView:self];
}
-(NSRect)rectForPoint:(NSPoint)point {
NSTextView* textView = (NSTextView*)self.scrollView.documentView;
NSUInteger rectCount;
NSRectArray frameRects = [textView.layoutManager
rectArrayForCharacterRange: NSMakeRange(NSNotFound, 0)
withinSelectedCharacterRange: kNullRange
inTextContainer: textView.textContainer
rectCount: &rectCount
];
const CGFloat kWidth = NSWidth(self.bounds);
const CGFloat kHeight = NSHeight(frameRects[0]);
const CGFloat x = 0;
CGFloat y = point.y - fmod(point.y, kHeight);
//y += NSMinY(self.scrollView.contentView.bounds);
return NSMakeRect(x, y, kWidth, kHeight);
}
@end
PopoverController:
@interface PopoverController : NSViewController<NSPopoverDelegate>
@property (strong) NSPopover *popover;
@end
@implementation PopoverController
-(instancetype)init {
if ((self = [super init])) {
NSTextField *label = [NSTextField labelWithString:@"Pop!"];
[label setFrameOrigin:NSMakePoint(kPadding, kPadding)];
self.view = [[NSView alloc]
initWithFrame:NSMakeRect(
0, 0,
2 * kPadding + label.frame.size.width,
2 * kPadding + label.frame.size.height)];
[self.view addSubview:label];
self.popover = [[NSPopover alloc] init];
self.popover.contentViewController = self;
self.popover.behavior = NSPopoverBehaviorTransient;
}
return self;
}
-(void)showOver:(NSRect)anchor ofView:(NSView*)view {
[self.popover showRelativeToRect:anchor ofView:view preferredEdge:NSMaxYEdge];
}
Внутри основной раскадровки розетка ViewController's scene has an
NSScrollView as a descendent view, connected to the
ViewController 's
scrollView`.