Хобрук: Ваш путь к мастерству в программировании

Как правильно настроить прокрутку NSTableView с помощью Auto Layout? То, что я пробовал, имеет странные глюки

Я пытаюсь использовать Auto Layout для настройки прокрутки в NSScrollView для прокрутки NSTableView на основе представления. У меня есть несколько проблем.

Самый очевидный: если видны все строки, таблицу можно прокрутить на одну строку вниз. Например, возьмите эти снимки программы до и после в конце этого поста:

ДоПосле

Я предполагаю, что NSTableHeaderView перекрывает NSTableView, но я попытался добавить ограничения, которые устанавливают верхнюю часть NSClipView NSTableView как в нижнюю часть представления заголовка, так и в его суперпредставление (еще один NSClipView, согласно экспериментам). Это ничего не изменило; кажется, что ограничения просто игнорируются.

Изменение размера окна до минимума, по-видимому, также выталкивает эту первую строку из представления, создавая второе изображение, когда вы снова увеличиваете окно.

Горизонтальная прокрутка также не работает или очень глючит, но мне интересно, связано ли это с автоматическим изменением размера столбца.

Это в OS X 10.11, но должно работать еще в 10.8. Это НЕ iOS.

Спасибо!

// 22 june 2016
#import <Cocoa/Cocoa.h>

NSLayoutConstraint *mkConstraint(id view1, NSLayoutAttribute attr1, NSLayoutRelation relation, id view2, NSLayoutAttribute attr2, CGFloat multiplier, CGFloat c)
{
    return [NSLayoutConstraint constraintWithItem:view1
        attribute:attr1
        relatedBy:relation
        toItem:view2
        attribute:attr2
        multiplier:multiplier
        constant:c];
}

@interface tableModel : NSObject<NSTableViewDataSource, NSTableViewDelegate>
@end

@implementation tableModel

- (NSInteger)numberOfRowsInTableView:(NSTableView *)tv
{
    return 15;
}

 - (NSView *)tableView:(NSTableView *)table viewForTableColumn:(NSTableColumn *)c row:(NSInteger)row
{
    NSTableCellView *tv;
    NSTextField *tf;

    tv = [[NSTableCellView alloc] initWithFrame:NSZeroRect];

    tf = [[NSTextField alloc] initWithFrame:NSZeroRect];
    [tf setStringValue:[NSString stringWithFormat:@"Row %d", ((int) (row + 1))]];
    [tf setEditable:NO];
    [tf setSelectable:NO];
    [tf setDrawsBackground:NO];
    [tf setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
    [tf setBordered:NO];
    [tf setBezelStyle:NSTextFieldSquareBezel];
    [tf setBezeled:NO];
    [[tf cell] setLineBreakMode:NSLineBreakByClipping];
    [[tf cell] setScrollable:YES];

    [tf setTranslatesAutoresizingMaskIntoConstraints:NO];
    [tv addSubview:tf];
    [tv addConstraint:mkConstraint(tv, NSLayoutAttributeLeading,
        NSLayoutRelationEqual,
        tf, NSLayoutAttributeLeading,
        1, -2)];
    [tv addConstraint:mkConstraint(tv, NSLayoutAttributeTrailing,
        NSLayoutRelationEqual,
        tf, NSLayoutAttributeTrailing,
        1, 3)];
    [tv addConstraint:mkConstraint(tv, NSLayoutAttributeCenterY,
        NSLayoutRelationEqual,
        tf, NSLayoutAttributeCenterY,
        1, 0)];

    [tv setTranslatesAutoresizingMaskIntoConstraints:NO];
    return tv;
}

@end

NSTableColumn *mkColumn(NSString *title)
{
    NSTableColumn *c;

    c = [[NSTableColumn alloc] initWithIdentifier:@""];
    // via Interface Builder
    [c setResizingMask:(NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask)];
    [c setTitle:title];
    [[c headerCell] setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
    return c;
}

NSTableView *mkTableView(void)
{
    NSTableView *tv;
    tableModel *model;

    tv = [[NSTableView alloc] initWithFrame:NSZeroRect];

    model = [tableModel new];
    [tv setDataSource:model];
    [tv setDelegate:model];
    [tv reloadData];

    [tv setAllowsColumnReordering:NO];
    [tv setAllowsColumnResizing:YES];
    [tv setAllowsMultipleSelection:NO];
    [tv setAllowsEmptySelection:YES];
    [tv setAllowsColumnSelection:NO];
    [tv setUsesAlternatingRowBackgroundColors:YES];
    [tv setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleRegular];
    [tv setGridStyleMask:NSTableViewGridNone];
    [tv setAllowsTypeSelect:YES];

    // needed to allow the table to grow vertically beyond showing all rows
    [tv setContentHuggingPriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationVertical];

    return tv;
}

NSScrollView *mkScrollView(NSView *dv)
{
    NSScrollView *sv;
    NSView *cv;

    sv = [[NSScrollView alloc] initWithFrame:NSZeroRect];
    [sv setBackgroundColor:[NSColor colorWithCalibratedWhite:1.0 alpha:1.0]];
    [sv setDrawsBackground:YES];
    [sv setBorderType:NSBezelBorder];
    [sv setAutohidesScrollers:YES];
    [sv setHasHorizontalRuler:NO];
    [sv setHasVerticalRuler:NO];
    [sv setRulersVisible:NO];
    [sv setScrollerKnobStyle:NSScrollerKnobStyleDefault];
    [sv setScrollsDynamically:YES];
    [sv setFindBarPosition:NSScrollViewFindBarPositionAboveContent];
    [sv setUsesPredominantAxisScrolling:NO];
    [sv setHorizontalScrollElasticity:NSScrollElasticityAutomatic];
    [sv setVerticalScrollElasticity:NSScrollElasticityAutomatic];
    [sv setAllowsMagnification:NO];

    [dv setTranslatesAutoresizingMaskIntoConstraints:NO];
    [sv setDocumentView:dv];

    cv = [sv contentView];
    [sv addConstraint:mkConstraint(dv, NSLayoutAttributeLeading,
        NSLayoutRelationEqual,
        cv, NSLayoutAttributeLeading,
        1, 0)];
    [sv addConstraint:mkConstraint(dv, NSLayoutAttributeTop,
        NSLayoutRelationEqual,
        cv, NSLayoutAttributeTop,
        1, 0)];
    [sv addConstraint:mkConstraint(dv, NSLayoutAttributeTrailing,
        NSLayoutRelationGreaterThanOrEqual,
        cv, NSLayoutAttributeTrailing,
        1, 0)];
    [sv addConstraint:mkConstraint(dv, NSLayoutAttributeBottom,
        NSLayoutRelationGreaterThanOrEqual,
        cv, NSLayoutAttributeBottom,
        1, 0)];

    return sv;
}

@interface appDelegate : NSObject<NSApplicationDelegate>
@end

@implementation appDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)note
{
    NSWindow *w;
    NSView *contentView;
    NSTableView *tv;
    NSScrollView *sv;

    w = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 320, 240)
        styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)
        backing:NSBackingStoreBuffered
        defer:YES];
    contentView = [w contentView];

    tv = mkTableView();
    [tv addTableColumn:mkColumn(@"Column")];
    sv = mkScrollView(tv);
    [sv setTranslatesAutoresizingMaskIntoConstraints:NO];
    [contentView addSubview:sv];

    [contentView addConstraint:mkConstraint(contentView, NSLayoutAttributeLeading,
        NSLayoutRelationEqual,
        sv, NSLayoutAttributeLeading,
        1, -20)];
    [contentView addConstraint:mkConstraint(contentView, NSLayoutAttributeTop,
        NSLayoutRelationEqual,
        sv, NSLayoutAttributeTop,
        1, -20)];
    [contentView addConstraint:mkConstraint(contentView, NSLayoutAttributeTrailing,
        NSLayoutRelationEqual,
        sv, NSLayoutAttributeTrailing,
        1, 20)];
    [contentView addConstraint:mkConstraint(contentView, NSLayoutAttributeBottom,
        NSLayoutRelationEqual,
        sv, NSLayoutAttributeBottom,
        1, 20)];

    [w makeKeyAndOrderFront:nil];
}

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app
{
    return YES;
}

@end

int main(void)
{
    NSApplication *app;

    app = [NSApplication sharedApplication];
    [app setActivationPolicy:NSApplicationActivationPolicyRegular];
    [app setDelegate:[appDelegate new]];
    [app run];
    return 0;
}

  • Вы пытались оставить translatesAutoresizingMaskIntoConstraints для представления документа при добавлении его в представление прокрутки и не устанавливать ограничения? Общее правило заключается в том, что когда вы передаете представление другому представлению или контроллеру для размещения в иерархии представлений (конечно, кроме addSubview:), получатель несет ответственность за отключение translatesAutoresizingMaskIntoConstraints и добавление ограничений по своему усмотрению. Аналогичным образом обратите внимание, что при создании табличного представления в IB ограничения на табличное представление отсутствуют (даже после добавления отсутствующих ограничений). 23.06.2016
  • Да; Я боялся, что это была ситуация. Я думал, что если мы сами явно не используем Auto Layout, это означает, что представление прокрутки вообще не будет использовать ограничения, и я предположил, что это приведет к проблемам смешивания ограничений и масок автоматического изменения размера в одном окне. С автоматическим изменением размеров масок, наверное, будет проще, да... 23.06.2016
  • Хм? Что заставляет вас думать, что вам нужно вернуться к использованию масок с автоматическим изменением размера? 23.06.2016
  • Э-э, я имел в виду, что думал, что если бы я не использовал Auto Layout, представление прокрутки тоже не было бы, и вместо этого it использовало бы маски автоматического изменения размера. Может быть, я неправильно интерпретирую свои собственные ошибки для проблем, которые возникают, когда вы смешиваете и сочетаете? 23.06.2016
  • Дело в том, что вы не знаете, и вам все равно, что использует прокрутка внутри. Вот почему вы должны использовать наиболее совместимый с предыдущими версиями подход (оставив translatesAutoresizingMaskIntoConstraints включенным) при передаче представления другому коду для включения в иерархию представлений. Этот другой код может отключить его и установить ограничения для себя, или он может не знать об автоматической компоновке и оставить ее включенной и настроить маски автоматического изменения размера. В любом случае, это не ваша проблема. Вы можете продолжать использовать автоматическую компоновку для остальной части иерархии представлений, если хотите. 23.06.2016
  • Ах, приятно знать. Я никогда не думал об этом таким образом ^^ Я просто верну все элементы автоматического макета в вид прокрутки и надеюсь, что все сработает хорошо, и это просто я неправильно запомнил наблюдения, основанные на моем собственном коде с ошибками. Спасибо! 23.06.2016
  • Дело в том, что если я изменяю размер окна на достаточно маленький (или даже если начальный размер достаточно мал), строка 0 исчезает под заголовком, все еще происходит даже без автоматического макета. Это известная проблема? 23.06.2016

Новые материалы

Создание кнопочного меню с использованием HTML, CSS и JavaScript
Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

Внедрите OAuth в свои веб-приложения для повышения безопасности
OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

Классы в JavaScript
class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

Как свинг-трейдеры могут использовать ИИ для больших выигрышей
По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

Как построить любой стол
Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...

Обзор: Машинное обучение: классификация
Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

Разработка расширений Qlik Sense с qExt
Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..