NSSplitView: управление положением делителя при изменении размера окна - PullRequest
13 голосов
/ 28 февраля 2012

У меня есть NSSplitView, у которого есть две панели - вид боковой панели слева и вид веб-страницы справа. У меня также есть набор делегатов, который обрабатывает ограничения для боковой панели, например:

- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex {
    return 500.0f;
}

- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
    return 175.0f;
}

- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview {
    return NO;
}

Это означает, что боковая панель может быть изменена только между 175 и 500 пикселями, и это прекрасно работает при использовании ручки делителя. Но при изменении размера всего окна разделитель перемещается из этих ограничений.

Кто-нибудь знает, как это контролировать?

Дополнительно: если я хочу сохранить выбранную пользователем ширину боковой панели, целесообразно ли считать ее, сохранить ее в файле настроек и восстановить ее позже, или есть более простой способ сделать это ? Я заметил, что в некоторых случаях состояние окна сохраняется - это обычно происходит или мне нужно его контролировать?

Заранее спасибо

Arne

Ответы [ 9 ]

4 голосов
/ 04 марта 2012

То, что вы ищете:

- (void)splitView:(NSSplitView*)sender resizeSubviewsWithOldSize:(NSSize)oldSize

[sender frame] будет новым размером вашего NSSplitView после изменения размера.Затем просто перенастройте ваши подпредставления соответственно.

3 голосов
/ 02 января 2016

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

Затем я изменил свойподход и нашел чистое и чрезвычайно простое решение.Я просто устанавливаю константу автоматического размещения для ширины (> = до желаемого минимального размера ) на NSView для одной стороны NSSplitView.Я сделал то же самое на другой стороне.С этими двумя простыми ограничениями NSSplitView отлично работал без необходимости делегировать вызовы.

3 голосов
/ 28 мая 2015

Проблема в том, что при изменении размера самого NSSplitView вызывается -adjustSubviews для выполнения работы, но он просто игнорирует ограничения min / max от делегата!

Однако -setPosition:ofDividerAtIndex: учитывает ограничения.

Все, что вам нужно сделать, это объединить оба - в этом примере предполагается, что NSSplitView имеет только 2 вида:

- (CGFloat)splitView:(NSSplitView*)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
  return 300;
}

- (CGFloat)splitView:(NSSplitView*)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
  return (splitView.vertical ? splitView.bounds.size.width : splitView.bounds.size.height) - 500;
}

- (void)splitView:(NSSplitView*)splitView resizeSubviewsWithOldSize:(NSSize)oldSize {
  [splitView adjustSubviews];  // Use default resizing behavior from NSSplitView
  NSView* view = splitView.subviews.firstObject;
  [splitView setPosition:(splitView.vertical ? view.frame.size.width : view.frame.size.height) ofDividerAtIndex:0];  // Force-apply constraints afterwards
}

Похоже, что это нормально работает в OS X 10.8, 10.9 и 10.10 и намного чище, чем другие подходы, так как это минимальный код и ограничения не дублируются.

2 голосов
/ 04 сентября 2014

Альтернативный способ решить эту проблему - использовать splitView:shouldAdjustSizeOfSubview:

Я обнаружил, что это намного проще для моих целей.

Например, если вы хотите, чтобы sidebarTableView никогда не былменьше вашей минимальной ширины 175, тогда вы можете сделать что-то вроде этого (при условии, что вы сделали sidebarTableView выходом на вашем контроллере / делегате представления);

- (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)subview
{
    if ((subview==self.sidebarTableView) && subview.bounds.size.width<=175) {
        return NO;
    }
    return YES;
}
1 голос
/ 08 ноября 2012

Вот моя реализация -splitView:resizeSubviewsWithOldSize::

-(void)splitView:(NSSplitView *)splitView resizeSubviewsWithOldSize:(NSSize)oldSize {
    if (![splitView isSubviewCollapsed:self.rightView] &&
        self.rightView.frame.size.width < 275.0f + DBL_EPSILON) {
        NSSize splitViewFrameSize = splitView.frame.size;
        CGFloat leftViewWidth = splitViewFrameSize.width - 275.0f - splitView.dividerThickness;
        self.leftView.frameSize = NSMakeSize(leftViewWidth,
                                             splitViewFrameSize.height);
        self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
                                          0.0f,
                                          275.0,
                                          splitViewFrameSize.height);
    } else
        [splitView adjustSubviews];
}

В моем случае, rightView - это второе из двух подпредставлений, которое является разборным с минимальной шириной 275,0.leftView не имеет минимума или максимума и не является складным.

0 голосов
/ 10 ноября 2017

Мне просто нужно было сделать это, и я предложил этот метод, который немного проще, чем в предыдущих примерах.В этом коде предполагается, что существуют IBOutlets для левого и правого NSScrollViews контейнера NSSplitView, а также константы CGFloat для минимального размера левого и правого представлений.

#pragma mark - NSSplitView sizing override

//------------------------------------------------------------------------------
// This is implemented to ensure that when the window is resized that our main table
// remains at it's smallest size or larger (the default proportional sizing done by
// -adjustSubviews would size it smaller w/o -constrainMinCoordiante being called).

- (void) splitView: (NSSplitView *)inSplitView resizeSubviewsWithOldSize: (NSSize)oldSize
{
    // First, let the default proportional adjustments take place
    [inSplitView adjustSubviews];

    // Then ensure that our views are at least their min size
    // *** WARNING: this does not handle allowing the window to be made smaller than the total of the two views!

    // Gather current sizes
    NSSize leftViewSize = self.leftSideView.frame.size;
    NSSize rightViewSize = self.rightSideView.frame.size;
    NSSize splitViewSize = inSplitView.frame.size;
    CGFloat dividerWidth = inSplitView.dividerThickness;

    // Assume we don't have to resize anything
    CGFloat newLeftWidth = 0.0f;

    // Always adjust the left view first if we need to change either view's size
    if( leftViewSize.width < kLeftSplitViewMinSize )
    {
        newLeftWidth = kLeftSplitViewMinSize;
    }
    else if( rightViewSize.width < kRightSplitViewMinSize )
    {
        newLeftWidth = splitViewSize.width - (kRightSplitViewMinSize + dividerWidth);
    }

    // Do we need to adjust the size?
    if( newLeftWidth > 0.0f )
    {
        // Yes, do so by setting the left view and setting the right view to the space left over
        leftViewSize.width = newLeftWidth;
        rightViewSize.width = splitViewSize.width - (newLeftWidth + dividerWidth);

        // We also need to set the origin of the right view correctly
        NSPoint origin = self.rightSideView.frame.origin;
        origin.x = splitViewSize.width - rightViewSize.width;
        [self.rightSideView setFrameOrigin: origin];

        // Set the the ajusted view sizes
        leftViewSize.height = rightViewSize.height = splitViewSize.height;
        [self.leftSideView setFrameSize: leftViewSize];
        [self.rightSideView setFrameSize: rightViewSize];
    }
}
0 голосов
/ 26 августа 2016

Я добился такого поведения, установив holdingPriority на NSSplitViewItem в Обязательное (1000) для фиксированной стороны в Интерфейсном Разработчике. Затем вы можете контролировать ширину для фиксированной стороны, установив ограничение на базовый NSView.

0 голосов
/ 31 августа 2015

Может быть, слишком поздно для вечеринки, однако это моя реализация resizeSubviewWithOldSize:.В моем проекте мне нужен NSplitView с изменяемым размером по вертикали с шириной leftView между 100.0 и 300.0;«Свертывание» не учитывается.Вы должны позаботиться о всех возможных измерениях для подпредставлений.

-(void)splitView:(NSSplitView *)splitView resizeSubviewsWithOldSize:(NSSize)oldSize {
    if (self.leftView.frame.size.width >= kMaxLeftWidth) {
        NSSize splitViewFrameSize = splitView.frame.size;
        CGFloat leftViewWidth = kMaxLeftWidth;
        CGFloat rightViewWidth = splitViewFrameSize.width - leftViewWidth - splitView.dividerThickness;

        self.leftView.frameSize = NSMakeSize(leftViewWidth,
                                             splitViewFrameSize.height);

        self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
                                          0.0f,
                                          rightViewWidth,
                                          splitViewFrameSize.height);
    } else if (self.leftView.frame.size.width <= kMinLeftWidth) {
        NSSize splitViewFrameSize = splitView.frame.size;
        CGFloat leftViewWidth = kMinLeftWidth;
        CGFloat rightViewWidth = splitViewFrameSize.width - leftViewWidth - splitView.dividerThickness;

        self.leftView.frameSize = NSMakeSize(leftViewWidth,
                                             splitViewFrameSize.height);

        self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
                                          0.0f,
                                          rightViewWidth,
                                          splitViewFrameSize.height);
    } else {
        NSSize splitViewFrameSize = splitView.frame.size;
        CGFloat leftViewWidth = self.leftView.frame.size.width;
        CGFloat rightViewWidth = splitViewFrameSize.width - leftViewWidth - splitView.dividerThickness;

        self.leftView.frameSize = NSMakeSize(leftViewWidth,
                                             splitViewFrameSize.height);

        self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
                                          0.0f,
                                          rightViewWidth,
                                          splitViewFrameSize.height);
    }
}
0 голосов
/ 22 мая 2014

Я использовал

- (void)splitView:(NSSplitView*)sender resizeSubviewsWithOldSize:(NSSize)oldSize

, но вместо изменения фрейма подпредставления я использовал

    [sender setPosition:360 ofDividerAtIndex:0]; //or whatever your index and position should be

Изменение фрейма не дало мне последовательных результатов.Установку положения делителя сделал.

...