随着NSRulerView滚动移动NSPopover

时间:2019-04-08 04:31:00

标签: objective-c cocoa scroll nspopover

背景

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`出口。

0 个答案:

没有答案