NSTextView внутри прокрутки блоков NSTableView

У меня есть NSTableView, а в каждой строке таблицы есть NSTextView. Я отключил прокрутку на NSTextView в своей раскадровке. Я могу нормально прокручивать NSTableView, но когда курсор мыши оказывается над NSTextView, прокрутка останавливается. Я предполагаю, что это связано с тем, что NSTextView перехватывает поведение прокрутки.

Стрелка указывает на NSTextView:

Стрелка указывает на NSTextView

Имейте в виду, что NSTextView находится в подклассе NSTableViewCell.

class AnnouncementsVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
  @IBOutlet weak var tableView: NSTableView!

  override func viewDidLoad() {
    //...
  }
  func numberOfRows(in tableView: NSTableView) -> Int {
    //...
  }
  func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
    //...
  }
}

class AnnouncementTableCell: NSTableCellView{
  @IBOutlet weak var message: NSTextView!
}

Как заставить NSTextView передавать свои события прокрутки своему родителю NSTableView? Я предполагаю, что мне понадобится scrollWheel(with event: NSEvent), но я не уверен, куда он пойдет, так как у меня здесь два разных класса.


person Clifton Labrum    schedule 09.08.2017    source источник
comment
Вам нужен NSTextView или вы можете использовать многострочный NSTextField?   -  person Willeke    schedule 09.08.2017
comment
Я выбрал NSTextView, чтобы можно было настроить высоту строки. Я полагаю, что мог бы использовать NSTextField и вместо этого использовать строку с атрибутами.   -  person Clifton Labrum    schedule 09.08.2017


Ответы (2)


Одним из способов добиться этого было бы создать подкласс NSScrollView и реализовать scrollWheel: для условного (1) либо использования событий прокрутки в вашем экземпляре подкласса по мере необходимости, либо (2) перенаправления их во вмещающее окно прокрутки на основе текущей позиции прокрутки ваших экземпляров.

Вот довольно рудиментарная реализация (Obj-C), которую я использовал в прошлом:

- (void)scrollWheel:(NSEvent *)e {


    if(self.enclosingScrollView) {

        NSSize
        contSize = self.contentSize,
        docSize = [self.documentView bounds].size,
        scrollSize = NSMakeSize(MAX(docSize.width  - contSize.width, 0.0f),
                                MAX(docSize.height - contSize.height,0.0f) );

        NSPoint
        scrollPos = self.documentVisibleRect.origin,
        normPos = NSMakePoint(scrollSize.width  ? scrollPos.x/scrollSize.width  : 0.0,
                              scrollSize.height ? scrollPos.y/scrollSize.height : 0.0 );

        if( ((NSView*)self.documentView).isFlipped ) normPos.y = 1.0 - normPos.y;

        if(   ( e.scrollingDeltaX>0.0f && normPos.x>0.0f) 
           || ( e.scrollingDeltaX<0.0f && normPos.x<1.0f)
           || ( e.scrollingDeltaY<0.0f && normPos.y>0.0f)
           || ( e.scrollingDeltaY>0.0f && normPos.y<1.0f) ) {

            [super scrollWheel:e];

        }
        else

            [self.nextResponder scrollWheel:e];

    }
    else 
        // Don't bother when not nested inside another NSScrollView
        [super scrollWheel:e];
}

Это все еще оставляет желать лучшего, например, независимая обработка компонентов deltaX и deltaY, но, возможно, этого достаточно для вашего случая.

person arri    schedule 11.09.2017
comment
Я нашел Swift, эквивалентный тому, который я опубликую в качестве дополнительного ответа, но по сути я делаю то же самое, что вы описали. Спасибо! - person Clifton Labrum; 07.02.2019

Вот версия Swift (4.2), которая отлично работает:

class MyScrollClass: NSScrollView{
  override func scrollWheel(with event: NSEvent) {
    self.nextResponder?.scrollWheel(with: event)
  }
}

Просто добавьте этот подкласс к вашему NSScrollView, и он должен работать.

person Clifton Labrum    schedule 07.02.2019
comment
в моем случае это был WKWebView, который воровал прокрутку, поэтому я создал подкласс WKWebView и переопределил scrollWheel() следующим образом. Благодарю. - person Little Watchman; 20.03.2020