首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >调整窗口大小时,保持缩放NSScrollView的内容居中并可见

调整窗口大小时,保持缩放NSScrollView的内容居中并可见
EN

Stack Overflow用户
提问于 2019-05-02 10:13:04
回答 1查看 499关注 0票数 0

我试图放大包含NSScrollViewNSTextView,并将其始终保持在其内容的中心。NSTextView有左/右插入,以保持单词包装一致,并将段落保持在视图的中心位置。

[NSScrollView scaleUnitSquareToSize:...]setMagnification:...都有自己的怪癖和问题,但就目前而言,setMagnification似乎是一个更好的选择,因为它不是相对的。

下面是发生的事情(以及其他奇怪的事情):

在调整大小时,我更新嵌入:

代码语言:javascript
复制
CGFloat inset = self.textScrollView.frame.size.width / 2 - _documentWidth / 2;
self.textView.textContainerInset = NSMakeSize(inset, TEXT_INSET_TOP);
self.textView.textContainer.size = NSMakeSize(_documentWidth, self.textView.textContainer.size.height);

放大:

代码语言:javascript
复制
CGFloat magnification = [self.textScrollView magnification];
NSPoint center = NSMakePoint(self.textScrollView.frame.size.width / 2, self.textScrollView.frame.size.height / 2);

if (zoomIn) magnification += .05; else magnification -= .05;
[self.textScrollView setMagnification:magnification centeredAtPoint:center];

一切都会持续一段时间。有时,取决于窗口从哪个窗口角调整大小,ScrollView失去了它的中心,而且我还没有找到重新对放大的NSScrollView视图进行中心化的解决方案。

放大后,当调整窗口大小时,布局约束也会被打破,特别是当textContainer被剪裁出视图时,应用程序崩溃时会出现以下错误:*** Assertion failure in -[NSISLinearExpression addVariable:coefficient:], /Library/Caches/com.apple.xbs/Sources/Foundation/Foundation-1349.91/Layout.subproj/IncrementalSimplex/NSISLinearExpression.m:716

一个问题可能是,我正在根据UIScrollView帧大小设置嵌入式,因为包含的NSTextView坐标似乎不是相对的,而是放大后的绝对坐标。

有什么安全的方法来放大这种观点,并使其始终保持其内容的中心?为什么我的限制被打破了?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-05-06 21:52:46

我也遇到过类似的问题,不幸的是,我最终还是以自己为中心。以下是我的解决方案的一些亮点。

  1. 需要预防复发!(否则堆栈溢出:)
  2. 创建一个不可绘制的NSView作为documentView,然后将您的可绘制视图添加为一个以手动居中的子视图,并手动将框架设置为父视图的visibleRect。
  3. 重写visibleRect,如果它无效,第二次调用它,并调试以确保它是有效的!
  4. 放大分层背景色。您可以尝试使用NSTiledLayer,但我已经多次尝试并放弃了该解决方案。

代码如下:

代码语言:javascript
复制
@interface FlippedParentView : NSView
@end

@implementation FlippedParentView
- (BOOL) isFlipped { return YES; }
@end




- (void)awakeFromNib
{
    [self resetMouseInfo];
    [[self window] setAcceptsMouseMovedEvents:YES];
    needsFullRedraw = YES;
    [self setAcceptsTouchEvents:YES];

    // problem: when zoomed-in, CALayer backed NSOpenGLView becomes too large
    // and hurts performance.
    // solution: create a fullsizeView for the NSScrollView to resize,
    // and make NSOpenGLView a subview.  Keep NSOpenGLView size the same as visibleRect,
    // positioning it as needed on the fullsizeView.
    NSScrollView *scrollvw = [self enclosingScrollView];
    [scrollvw setBackgroundColor:[NSColor darkStrokeColor]];
    fullsizeView = [[FlippedParentView alloc] initWithFrame: [self frame]];
    [scrollvw setDocumentView:fullsizeView];
    [fullsizeView setAutoresizesSubviews:NO];
    //printf("mask %d\n", [self autoresizingMask]);
    [fullsizeView setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable | NSViewMinYMargin | NSViewMaxYMargin | NSViewMaxXMargin | NSViewMinXMargin];
    [self setAutoresizingMask: NSViewNotSizable];
    [fullsizeView addSubview:self];
}

- (NSRect) visibleRect
{
    NSRect visRect = [super visibleRect];
    if ( visRect.size.width == 0 )
    {
        visRect = [[self superview] visibleRect];
        if ( visRect.size.width == 0 )
        {
            // this jacks up everything
            DUMP( @"bad visibleRect" );
        }
        visRect.origin = NSZeroPoint;
    }
    return visRect;
}

- (void) _my_zoom: (double)newZoom
{
    mouseFocusPt = [self focusPt];
    NSRect oldVisRect = [[self superview] visibleRect];
    if ( newZoom < 1.0 )
        newZoom = 1.0;
    if ( newZoom > kZoomFactorMax ) newZoom = kZoomFactorMax;

    float xpct = (mouseFocusPt.x - oldVisRect.origin.x) /
    ( NSMaxX(oldVisRect) - oldVisRect.origin.x );

    float ypct = (mouseFocusPt.y  - oldVisRect.origin.y) /
    ( NSMaxY(oldVisRect) - oldVisRect.origin.y );

    float oldZoom = zoomFactor;

    zoomFactor = newZoom;

    /////////////////////////////////////////////////////////////////////////////////////////////////////
    // Stay locked on users' relative mouse location, so user can zoom in and back out without
    // the view scrolling out from under the mouse location.
    NSPoint newFocusPt = NSMakePoint (mouseFocusPt.x * newZoom/oldZoom,
                                      mouseFocusPt.y * newZoom/oldZoom) ;

    NSRect myFrame = fullsizeFrame; // [self frame];
    float marginPercent = (myFrame.size.height - drawableSizeWithMargins.height) / drawableSizeWithMargins.height;

    [self updateContext];

    NSRect newVisRect;
    newVisRect.size = [self visibleRect].size;
    newVisRect.origin.x = (newFocusPt.x) - (xpct * newVisRect.size.width);
    //DLog( @"xpct %0.2f, zoomFactor %0.2f, newVisRect.origin.x %0.2f", xpct, zoomFactor, newVisRect.origin.x);

    myFrame = fullsizeFrame; // [self frame];
    float marginPercent2 = (myFrame.size.height - drawableSizeWithMargins.height) / drawableSizeWithMargins.height;
    float marginDiff = (marginPercent - marginPercent2) * drawableSizeWithMargins.height;
    newVisRect.origin.y = (newFocusPt.y ) - (ypct * newVisRect.size.height) - marginDiff;
    //DLog( @"ypct %0.2f, zoomFactor %0.2f, newVisRect.origin.y %0.2f", ypct, zoomFactor, newVisRect.origin.y);
    //DLog( @"marginPercent %0.2f newVisRect %@", marginPercent, NSStringFromRect(newVisRect) );
    if ( newVisRect.origin.x < 1 ) newVisRect.origin.x = 1;
    if ( newVisRect.origin.y < 1 ) newVisRect.origin.y = 1;


     //   NSLog( @"zoom scrollRectToVisible %@ bounds %@", NSStringFromRect(newVisRect), NSStringFromRect([[self superview] bounds]) );
    // if ( iUseMousePt || isSlider )
        [[self superview] scrollRectToVisible:newVisRect];
}

// - zoomFactor of 1.0 is defined as the zoomFactor needed to show entire selected context within visibleRect,
//   including margins of 5% of the context size
// - zoomFactor > 1.0 will make pixels look bigger (view a subsection of a larger total drawableSize)
// - zoomFactor < 1.0 will make pixels look smaller (selectedContext size will be less than drawableSize)
-(void)updateContext
{
    static BOOL sRecursing = NO;
    if ( sRecursing ) return; // prevent recursion
    sRecursing = YES;

    //NSRect scrollRect = [[self superview]  frame];
    NSRect clipViewRect = [[[self enclosingScrollView] contentView] frame];
    NSRect visRect = [[self superview] visibleRect]; // careful... visibleRect is sometimes NSZeroRect

    float layoutWidth = clipViewRect.size.width;
    float layoutHeight = clipViewRect.size.height;



    marginPct = layoutHeight / (layoutHeight - (overlayViewMargin*2) );

    // Satisfy the constraints fully-zoomed-out case:
    //  1) the drawable rect is centered in the view with at margins.
    //     Allow for 5% margins (1.025 = 2.5% left, right, top, bottom)
    //  2) guarantee the drawable rect does not overlap the mini-map in upper right corner.
    NSRect baseRect = NSZeroRect;
    baseRect.size = visRect.size;
    NSRect drawableBaseRect = getCenteredRectFloat(baseRect, metaUnionRect.size );

    //drawableSizeWithMargins = nsIntegralSize( nsScaleSize( drawableBaseRect.size, zoomFactor ) );
    drawableSizeWithMargins = nsScaleSize( drawableBaseRect.size, zoomFactor );

    // drawableSize will NOT include the margins.  We loop until we've satisfied
    // the constraints above.
    drawableSize = drawableSizeWithMargins;

    do
    {
        NSSize shrunkSize;
        shrunkSize.width = layoutWidth / marginPct;
        shrunkSize.height = layoutHeight /  marginPct;
        //drawableSize = nsIntegralSize( nsScaleSize( drawableBaseRect.size, zoomFactor / marginPct ));
        drawableSize = nsScaleSize( drawableBaseRect.size, zoomFactor / marginPct );

        [self calculateMiniMapRect]; // get approx. size.  Will calculate once more below.

        NSRect shrunkRect = getCenteredRectNoScaling(baseRect, shrunkSize );

        // DLog( @"rough miniMapRect %@ shrunk %@", NSStringFromRect(miniMapRect), NSStringFromRect(shrunkRect));

        // make sure minimap doesn't overlap drawable when you scroll to top-left
        NSRect topMiniMapRect = miniMapRect;
        topMiniMapRect.origin.x -= visRect.origin.x;
        topMiniMapRect.origin.y = 0;
        if ( !NSIntersectsRect( topMiniMapRect, shrunkRect ) )
        {
            topMarginPercent = fabs(shrunkRect.origin.y - drawableBaseRect.origin.y)  / baseRect.size.height;
            break;
        }

        float topMarginOffset = shrunkRect.size.height + (baseRect.size.height * 0.025);
        shrunkRect.origin.y = NSMaxY(baseRect) - topMarginOffset;

        if ( !NSIntersectsRect( topMiniMapRect, shrunkRect ) )
        {
            topMarginPercent = fabs(shrunkRect.origin.y - drawableBaseRect.origin.y)  / baseRect.size.height;
            break;
        }

        marginPct *= 1.025;
    } while (1);

    fullsizeFrame.origin = NSZeroPoint;
    fullsizeFrame.size.width  = fmax(drawableSizeWithMargins.width, layoutWidth);
    fullsizeFrame.size.height = fmax(drawableSizeWithMargins.height, layoutHeight);

    [fullsizeView setFrame:fullsizeFrame];

    NSRect myNewFrame = [fullsizeView visibleRect];
    if (myNewFrame.size.width > 0)
       [self setFrame: myNewFrame]; //NSView

    sRecursing = NO;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55950198

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档