15

我有一个包裹在 NSScrollView (myScrollView) 中的 NSView (myView)。使用放大/缩小按钮,用户可以更改 myView 的比例。如果用户当前滚动到 myView 中的特定位置,我想在缩放发生后将该部分视图保留在屏幕上。

我的代码如下所示:

    // preserve current position in scrollview
    NSRect oldVisibleRect = [[myScrollView contentView] documentVisibleRect];
    NSPoint oldCenter = NSPointFromCGPoint(CGPointMake(oldVisibleRect.origin.x + (oldVisibleRect.size.width  / 2.0),
                                                       oldVisibleRect.origin.y + (oldVisibleRect.size.height / 2.0)));

    // adjust my zoom
    ++displayZoom;
    [self scaleUnitSquareToSize:NSSizeFromCGSize(CGSizeMake(0.5, 0.5))];
    [self calculateBounds];  // make sure my frame & bounds are at least as big as the visible content view
    [self display];

    // Adjust scroll view to keep the same position.
    NSRect newVisibleRect = [[myScrollView contentView] documentVisibleRect];
    NSPoint newOffset = NSPointFromCGPoint(CGPointMake((oldCenter.x * 0.5) - (newVisibleRect.size.width  / 2.0),
                                                       (oldCenter.y * 0.5) - (newVisibleRect.size.height / 2.0)));
    if (newOffset.x < 0)
        newOffset.x = 0;
    if (newOffset.y < 0)
        newOffset.y = 0;

    [[myScrollView contentView] scrollToPoint: newOffset];
    [myScrollView reflectScrolledClipView: [myScrollView contentView]];

它似乎有点接近,但它并不完全正确,我无法弄清楚我做错了什么。我的两个问题是:

1)是否没有内置的东西:

   [myView adjustScaleBy: 0.5 whilePreservingLocationInScrollview:myScrollView];

2)如果没有,任何人都可以看到我在上面的“漫长”方法中做错了什么吗?

谢谢!

4

3 回答 3

12

缩放后保持相同的滚动位置并不容易。您需要确定的一件事是您所说的“相同”是什么意思 - 您是否希望缩放前可见区域的顶部、中间或底部在缩放后保持原位?

或者,更直观地说,您是否希望在可见矩形下方保持一个百分比的位置等于您在开始时向下滚动文档的百分比(例如,因此滚动器拇指的中心不会向上移动或在一个规模下降,拇指只是增长或缩小)。

如果你想要后一种效果,一种方法是获取 NSScrollView 的verticalScroller 和horizo​​ntalScroller,然后读取它们的'floatValue'。这些从 0 到 1 标准化,其中“0”表示您位于文档的顶部,1 表示您位于文档的末尾。询问滚动条的好处是,如果文档比 NSScrollView 短,滚动条在所有情况下仍会为“floatValue”返回合理的答案,因此您不必对此进行特殊处理。

调整大小后,将 NSScrollView 的滚动位置设置为与缩放前相同的百分比 - 但是,遗憾的是,这里是我稍微挥手的地方。我有一段时间没有在我的代码中这样做了,但我记得你不能直接设置 NSScrollers 的“floatValue”——它们看起来会滚动,但它们实际上不会影响 NSScrollView。

因此,您必须编写一些数学运算,以根据您希望通过它的百分比来计算文档中的新左上角点 - 例如,在 y 轴上,它看起来像,“如果文档现在比 scrollView 的 contentView 短,滚动到 0 点,否则滚动到文档下方 ((contentView 的高度 - documentView 的高度) * oldVerticalPercentage) 的点。” X轴当然是类似的。

另外,我几乎肯定你不需要在这里调用 -display ,而且通常永远不应该调用它。(-setNeedsDisplay:最多。)

-会

于 2009-09-20T03:17:38.997 回答
7

我认为你喜欢打字太多...... ;-)

// instead of this:
NSPoint oldCenter = NSPointFromCGPoint(CGPointMake(oldVisibleRect.origin.x +
    (oldVisibleRect.size.width  / 2.0),

// use this:
NSPoint oldCenter = NSMakePoint(NSMidX(oldVisibleRect), NSMaxY(oldVisibleRect));

// likewise instead of this:
[self scaleUnitSquareToSize:NSSizeFromCGSize(CGSizeMake(0.5, 0.5))];

// use this:
[self scaleUnitSquareToSize:NSMakeSize(0.5, 0.5)];

// and instead of this
NSPoint newOffset = NSPointFromCGPoint(CGPointMake(
    (oldCenter.x * 0.5) - (newVisibleRect.size.width  / 2.0),
    (oldCenter.y * 0.5) - (newVisibleRect.size.height / 2.0)));

// use this:
NSPoint newOffset NSMakePoint(
    (oldCenter.x - NSWidth(newVisibleRect)) / 2.f,
    (oldCenter.y - NSHeight(newVisibleRect)) / 2.f);
于 2009-09-30T15:37:32.933 回答
7

这是一个老问题,但我希望寻找这个的人会发现我的答案很有用......

float zoomFactor = 1.3;

-(void)zoomIn
{
    NSRect visible = [scrollView documentVisibleRect];
    NSRect newrect = NSInsetRect(visible, NSWidth(visible)*(1 - 1/zoomFactor)/2.0, NSHeight(visible)*(1 - 1/zoomFactor)/2.0);
    NSRect frame = [scrollView.documentView frame];

    [scrollView.documentView scaleUnitSquareToSize:NSMakeSize(zoomFactor, zoomFactor)];
    [scrollView.documentView setFrame:NSMakeRect(0, 0, frame.size.width * zoomFactor, frame.size.height * zoomFactor)];

    [[scrollView documentView] scrollPoint:newrect.origin];
}

-(void)zoomOut
{
    NSRect visible = [scrollView documentVisibleRect];
    NSRect newrect = NSOffsetRect(visible, -NSWidth(visible)*(zoomFactor - 1)/2.0, -NSHeight(visible)*(zoomFactor - 1)/2.0);

    NSRect frame = [scrollView.documentView frame];

    [scrollView.documentView scaleUnitSquareToSize:NSMakeSize(1/zoomFactor, 1/zoomFactor)];
    [scrollView.documentView setFrame:NSMakeRect(0, 0, frame.size.width / zoomFactor, frame.size.height / zoomFactor)];

    [[scrollView documentView] scrollPoint:newrect.origin];
}
于 2011-06-16T05:40:58.257 回答