代码之家  ›  专栏  ›  技术社区  ›  Olie

更改比例时,如何在NSSollView中保持滚动位置?

  •  15
  • Olie  · 技术社区  · 16 年前

    我已经将一个NSView(myView)包装在一个NSScrollView(myScrollView)中。使用放大/缩小按钮,用户可以更改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]];
    

       [myView adjustScaleBy: 0.5 whilePreservingLocationInScrollview:myScrollView];
    

    3 回复  |  直到 16 年前
        1
  •  12
  •   Wil Shipley    16 年前

    缩放后保持相同的滚动位置并不容易。你需要决定的一件事是你所说的“相同”是什么意思——你希望缩放前可见区域的顶部、中部还是底部在缩放后保持不变?

    或者,更直观地说,你是否希望在可见矩形下方保持一个百分比的位置,等于你开始向下滚动文档时的百分比(例如,这样滚动者的拇指中心在缩放过程中不会上下移动,拇指只是增长或收缩)。

    如果你想要后一种效果,一种方法是获取NSSollView的verticalScroller和horizontalSoller,然后读取它们的'floatValue。这些值从0到1进行归一化,其中'0'表示你在文档的顶部,1表示你在末尾。向滚动器询问此事的好处是,如果文档比NSSollView短,滚动器在所有情况下都会为“floatValue”返回一个合理的答案,所以你不必对此进行特殊处理。

        2
  •  7
  •   sth    16 年前

    // 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);
    
        3
  •  7
  •   whooops    15 年前

    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];
    }