как настроить несколько расширяемых разделов в прокрутке

Мне нужен макет, похожий на Inspectors IB, где есть несколько расширяемых разделов, расширенных треугольниками раскрытия, и все они содержатся в прокрутке.

Если бы была нужна только одна расширяемая секция, я бы уже был там: я поместил расширяемую секцию в NSBox, дал коробке и всему, что над ней, верхнюю распорку, но не нижнюю, а всему, что под ней, дал нижнюю распорку, но не верхнюю. распорка Затем я настроил действие треугольника раскрытия, чтобы показать/скрыть поле и настроить размер кадра представления документа в прокрутке.

Но, похоже, нет способа установить распорки для нескольких блоков. Либо закрытие треугольников раскрытия оставляет зазоры, либо коробки скользят друг по другу.

Я взглянул на NSOutlineView, но это таблица; у него не может быть подпредставлений, таких как поля со списком и кнопки. (Или, может быть, это возможно, если я создам пользовательские ячейки, чего я еще не делал, но я подозреваю, что они не подходят для полнофункционального макета.)

Может ли кто-нибудь указать мне в правильном направлении?


person Wienke    schedule 23.03.2011    source источник


Ответы (2)


Ознакомьтесь с InspectorKit. Однако, если вы используете Xcode 4, имейте в виду, что он больше не поддерживает IBPlugins, поэтому вам придется использовать InspectorKit в коде (и обойтись без удобства перетаскивания плагина Interface Builder).

person Joshua Nozzi    schedule 23.03.2011
comment
Я бы предпочел избегать использования стороннего плагина, но первая функция, на которую меня натолкнула ваша ссылка, — это repositionViewsIgnoringView. Это то что мне нужно. И я думаю, что на самом деле я мог бы реализовать это сам; в коде я скорректирую начало координат Y всех затронутых секций на одинаковую величину, а в IB я уберу верхние/нижние распорки. Немного болезненно, но выполнимо. Спасибо за подсказку. - person Wienke; 23.03.2011

Если кто-то еще столкнется с этой проблемой дизайна, я опубликую IBAction, который придумал.

В этой схеме используются обычные неперевернутые представления. То есть начало координат находится в левом нижнем углу. При изменении docSize пробел добавляется или удаляется сверху.

В то время как для одного треугольника раскрытия некоторым элементам управления нужны верхние стойки, а некоторым — нижние, для этой схемы все элементы управления должны иметь как верхние, так и нижние стойки. В противном случае они подстраиваются автоматически, сбрасывая все со счетов.

Как отмечалось в конце, при полной прокрутке вниз возникает серьезная проблема. Но это другая глава…

/**
 Action called upon clicking a disclosure triangle.
 Hides or discloses the box associated with the disclosure triangle.
 */
- (IBAction) discloseBox:(id)sender {

// Determine which box is governed by this disclosure triangle.
NSBox *boxTarget;
switch ([sender tag]) {
    case kDT_Source:
        boxTarget = self.boxSourceInfo;
        break;
    case kDT_Tweak:
        boxTarget = self.boxTweak;
        break;
    case kDT_Series:
        boxTarget = self.boxSeries;
        break;
    case kDT_Abbrevs:
        boxTarget = self.boxAbbreviations;
        break;
    case kDT_Flag:
        boxTarget = self.boxFlaggingAndComments;
        break;
    default:
        break;
}

// Get size info on the content with and without the box.
NSView *docView = [self.svEditorMain documentView];
NSSize docSize = [docView frame].size;
CGFloat fHeightChange = [boxTarget frame].size.height;

// Before actually changing the content size, record what point is currently at the top of the window.
CGFloat dropFromTop_preChange = [self getCurrentDropFromTop];

// If the state is now on, make the box visible.
// If the state is now off, hide the box and make the height change negative.
switch ([sender state]) {
    case NSOnState:
        [boxTarget setHidden:NO];
        break;
    case NSOffState:
        [boxTarget setHidden:YES];
        fHeightChange *= -1;
        break;
    default:
        break;
}
// Use the height change to prepare the adjusted docSize, but don't apply it yet.
NSSize adjustedDocSize = NSMakeSize(docSize.width, (docSize.height + fHeightChange));

// Make sure the adjustees array is populated.
[self populateVerticalAdjusteesArray];

// If the height change is positive, expand the content size before adjusting the origins, so that the origins will have space to move up into. (Space will be added at top.)
if (fHeightChange > 0)
    [docView setFrameSize:adjustedDocSize];

// Get the current, pre-change Y origin of the target box.
CGFloat boxOriginY_preChange = [boxTarget frame].origin.y;
// Loop through the adjustees, adjusting their height.
NSControl *control;
CGFloat originX;
CGFloat originY;

for (NSUInteger ui = 0; ui < [self.carrVerticalAdjustees count]; ++ui) {
    control = [self.carrVerticalAdjustees objectAtIndex:ui];
    originY = [control frame].origin.y;
    // Adjust all controls that are above the origin Y of the target box (but do nothing to the target box itself).
    // Since coordinate system places origin at lower left corner, higher numbers are higher controls.
    if (originY > boxOriginY_preChange) {
        originX = [control frame].origin.x; // get originX just so you can assemble a new NSPoint
        originY += fHeightChange; 
        [control setFrameOrigin:NSMakePoint(originX, originY)];
    }
    // Since the array was assembled in order from top down, once a member is encountered whose origin is below the target's, we're done.
    else 
        break;
}

// If the height change is negative, contract the content size only now, after the origins have all been safely adjusted downwards. (Space will be removed at top.)
if (fHeightChange < 0)
    [docView setFrameSize:adjustedDocSize];

// Left to its own devices, the scroller will maintain the old distance from the bottom, so whatever is under the cursor will jump up or down. To prevent this, scroll the content to maintain the old distance from the TOP, as recorded above.
// (This won't work if user is already scrolled to the bottom and then collapses a box. The only way to maintain the scroll position then would be to add blank space at the bottom, which would require moving  the origin of all the content up. And then you would want to reverse those changes as soon as the blank space scrolled back out of view, which would require adding some trackers and monitoring NSViewBoundsDidChangeNotification.)
[self scrollMainTo:dropFromTop_preChange];  

}

person Wienke    schedule 25.03.2011