Как вы получаете NSScrollView для центра просмотра документа в 10.9 и более поздних версиях?

Есть много примеров того, как заставить NSScrollView центрировать свое представление документа. Вот два примера (которые настолько похожи, что кто-то копирует кого-то без атрибуции, но суть того, как есть). http://www.bergdesign.com/developer/index_files/88a764e343ce7190c4372d1425b3b6a3-0.html https://github.com/devosoft/avida/blob/master/apps/viewer-macos/src/main/CenteringClipView.h

Обычно это делается путем подкласса NSClipView и переопределения:

- (NSPoint)constrainScrollPoint:(NSPoint)newOrigin;

Но этот метод устарел в Mac OS X 10.9 +

Что мы можем сделать сейчас? Oh noes ~!

Ответ 1

Ну, ответ прост и нигде не близок, как раздутый. Тем не менее, они не работают с увеличением двойного крана.

Это так. Это просто работает. Вы также можете настроить свои настройки по мере необходимости.

В @implementation вам нужно только выполнить переопределение constrainBoundsRect:

- (NSRect)constrainBoundsRect:(NSRect)proposedClipViewBoundsRect {

    NSRect constrainedClipViewBoundsRect = [super constrainBoundsRect:proposedClipViewBoundsRect];

    // Early out if you want to use the default NSClipView behavior.
    if (self.centersDocumentView == NO) {
        return constrainedClipViewBoundsRect;
    }

    NSRect documentViewFrameRect = [self.documentView frame];

    // If proposed clip view bounds width is greater than document view frame width, center it horizontally.
    if (proposedClipViewBoundsRect.size.width >= documentViewFrameRect.size.width) {
        // Adjust the proposed origin.x
        constrainedClipViewBoundsRect.origin.x = centeredCoordinateUnitWithProposedContentViewBoundsDimensionAndDocumentViewFrameDimension(proposedClipViewBoundsRect.size.width, documentViewFrameRect.size.width);
    }

    // If proposed clip view bounds is hight is greater than document view frame height, center it vertically.
    if (proposedClipViewBoundsRect.size.height >= documentViewFrameRect.size.height) {

        // Adjust the proposed origin.y
        constrainedClipViewBoundsRect.origin.y = centeredCoordinateUnitWithProposedContentViewBoundsDimensionAndDocumentViewFrameDimension(proposedClipViewBoundsRect.size.height, documentViewFrameRect.size.height);
    }

    return constrainedClipViewBoundsRect;
}


CGFloat centeredCoordinateUnitWithProposedContentViewBoundsDimensionAndDocumentViewFrameDimension
(CGFloat proposedContentViewBoundsDimension,
 CGFloat documentViewFrameDimension )
{
    CGFloat result = floor( (proposedContentViewBoundsDimension - documentViewFrameDimension) / -2.0F );
    return result;
}

В @interface просто добавьте одно единственное свойство. Это позволяет не использовать центрирование. Как вы можете себе представить, может быть условная логика, которую вы хотите постепенно центрировать.

@property BOOL centersDocumentView;

Кроме того, не забудьте установить этот BOOL в YES или NO в своем переопределении

initWithFrame и initWithCoder:

поэтому у вас будет известное значение по умолчанию, которое будет работать.

(помните, что дети, initWithCoder:, позволяют вам делать необходимые действия и задавать класс просмотра в nib. Не забудьте вызвать супер до ваших вещей!)

Конечно, если вам нужно поддерживать что-либо раньше 10.9, вам нужно будет реализовать другой материал.

(хотя, вероятно, не так много, как другие...)

Ответ 2

Здесь рабочий класс для быстрого

class CenteredClipView:NSClipView
{
    override func constrainBoundsRect(proposedBounds: NSRect) -> NSRect {

        var rect = super.constrainBoundsRect(proposedBounds)
        if let containerView = self.documentView as? NSView {

            if (rect.size.width > containerView.frame.size.width) {
                rect.origin.x = (containerView.frame.width - rect.width) / 2
            }

            if(rect.size.height > containerView.frame.size.height) {
                rect.origin.y = (containerView.frame.height - rect.height) / 2
            }
        }

        return rect
    }
}

Ответ 3

1) убедитесь, что представление (documentView) прямо под клипом не имеет ограничений для просмотра клипа! (если это так, проверьте, удалите во время сборки)

2) подкласс NSClipView

@implementation CenterClipView

- (NSRect)constrainBoundsRect:(NSRect)proposedClipViewBoundsRect {

    NSRect rect = [super constrainBoundsRect:proposedClipViewBoundsRect];
    NSView * view = self.documentView;

    if (view) {

        if (rect.size.width > view.frame.size.width) {
            rect.origin.x = (rect.size.width - view.frame.size.width) / 2.;
        }

        if(rect.size.height > view.frame.size.height) {
            rect.origin.y = (rect.size.height - view.frame.size.height) / 2.;
        }
    }

    return rect;
}

@end

3) измените NSClipView на ваш подкласс

Ответ 4

Ответ выше учугака работает очень хорошо, и, как уже отмечалось, это намного проще, чем более старые решения.

Приведенный выше код вызывает функцию centeredCoordinateUnitWithProposedContentViewBoundsDimensionAndDocumentViewFrameDimension(), но источник для этого не предоставляется.

Функция тривиальна, но для полноты здесь реализована реализация:

CGFloat centeredCoordinateUnitWithProposedContentViewBoundsDimensionAndDocumentViewFrameDimension( CGFloat clipDimension, CGFloat docDimension)
{
    CGFloat newOrigin;
    newOrigin = roundf((docDimension - clipDimension) / 2.0);
    return newOrigin;
}