How do I properly set up a scrolling NSTableView using Auto Layout? What I've tried has odd glitches

社会主义新天地 提交于 2020-01-04 06:45:30

问题


I am trying to use Auto Layout to set up scrolling in NSScrollView to scroll a view-based NSTableView. I have a few issues.

The most obvious is: if all the rows are visible, the table can still be scrolled down by one row. For instance, take these before and after shots of the program at the end of this post:

I am guessing that the NSTableHeaderView is overlapping the NSTableView, but I tried adding constraints that set the top of the NSTableView's NSClipView to both the bottom of the header view and its superview (another NSClipView, according to experiments). That didn't change anything; it seems as if the constraints are simply ignored.

Resizing the window as small as possible seems to push that first row out of the view as well, producing the second image when you grow the window again.

Horizontal scrolling also doesn't work or is very glitchy, but I'm wondering if that's due to column autoresizing.

This is on OS X 10.11, but has to work as far back as 10.8. This is NOT iOS.

Thanks!

// 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;
}

来源:https://stackoverflow.com/questions/37979445/how-do-i-properly-set-up-a-scrolling-nstableview-using-auto-layout-what-ive-tr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!