15

有很多关于如何让 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 + 中已弃用

我们现在能做什么?哦不~!

4

4 回答 4

26

嗯,答案很简单,而且远没有那些过于臃肿。无论如何,这些都不适用于双击放大。

这样做。它只是工作。您还可以根据需要自定义调整。

@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;

另外,请务必将其设置BOOLYESNO覆盖

initWithFrameinitWithCoder:

所以你会有一个已知的默认值来工作。

记住孩子们, initWithCoder:让你做必要的事情并在笔尖中设置视图的类。不要忘记在你的东西之前调用 super!

当然,如果您需要支持早于 10.9 的任何内容,则需要实现其他内容。

(虽然可能没有其他人那么多......)

编辑:正如其他人所指出的,Apple 在https://developer.apple.com/library/archive/samplecode/Exhibition/Listings/Exhibition_CenteringClipView_swift有 Swift 中的示例代码(尽管从 2016 年开始,所以它可能不是当前的 Swift :D) .html

于 2014-02-27T14:54:29.663 回答
23

这里是 swift 的工人阶级

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
    }
}
于 2015-01-26T16:59:25.813 回答
2

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 更改为您的子类

于 2016-02-14T15:12:30.900 回答
1

uchuugaka 上面的答案非常有效,而且正如所指出的,它比旧的解决方案要简单得多。

上面的代码调用了 function centeredCoordinateUnitWithProposedContentViewBoundsDimensionAndDocumentViewFrameDimension(),但没有提供它的源代码。

该功能是微不足道的,但为了完整起见,这里有一个实现:

CGFloat centeredCoordinateUnitWithProposedContentViewBoundsDimensionAndDocumentViewFrameDimension( CGFloat clipDimension, CGFloat docDimension)
{
    CGFloat newOrigin;
    newOrigin = roundf((docDimension - clipDimension) / 2.0);
    return newOrigin;
}
于 2014-03-31T06:37:30.553 回答