Pergunta

Eu tenho um NSView (myView) envolto em uma NSScrollView (myScrollView). Utilização do zoom-in / out botões, o usuário pode alterar a escala de myView. Se o usuário está rolado para um ponto específico no myView, eu gostaria de manter essa parte da visão na tela após o zoom ocorreu.

Eu tenho o código que se parece com isso:

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

E parece tipo de perto, mas não é completamente certo e eu não consigo descobrir o que eu estou fazendo errado. Minhas duas perguntas são:

1) Não há um built-in algo ao longo das linhas de:

   [myView adjustScaleBy: 0.5 whilePreservingLocationInScrollview:myScrollView];

2) Se não, alguém pode ver o que estou fazendo de errado no meu "caminho mais longo" abordagem, acima?

Obrigado!

Foi útil?

Solução

Mantendo a mesma posição de rolagem após escala não é fácil. Uma coisa que você precisa decidir é o que você quer dizer com "o mesmo" - você quer o topo, meio ou na parte inferior da área visível antes de escalar para ficar no lugar depois de dimensionamento

?

Ou, de forma mais intuitiva, você quer a posição que permanece no lugar um percentual abaixo da rect visível igual à percentagem que você está rolado para baixo o documento quando você começar (por exemplo, de modo que o centro do polegar do scroller não mover para cima ou para baixo durante uma escala, o polegar apenas aumenta ou diminui).

Se você deseja que o último efeito, uma maneira de fazer isso é começar verticalScroller e horizontalScroller do NSScrollView, e em seguida, ler o seu 'floatValue de. Estes são normalizados de 0 a 1, onde '0' significa que você está no topo do documento e 1 significa que você está no final. A coisa agradável sobre perguntando o scroller para isto é que se o documento é menor que o NSScrollView, o scroller ainda retorna uma resposta sã em todos os casos para 'floatValue', então você não tem que especial caso isso.

Depois de redimensionar, ajustar a posição de rolagem do NSScrollView ser o mesmo percentual que era antes da escala - mas, infelizmente, aqui é onde eu acenar minhas mãos um pouco. Eu não fiz isso em um tempo no meu código, mas se bem me lembro você não pode apenas definir os NSScrollers' 'floatValue de diretamente -. Eles vão olhar deslocado, mas eles realmente não vai afetar o NSScrollView

Assim, você terá que escrever um pouco de matemática para calcular o novo ponto superior esquerdo no seu documento com base no percentual que você quer ser por ele - no eixo y, por exemplo, ele vai olhar como ", Se o documento é agora mais curto do que contentView do scrollView, desça para o ponto 0, caso contrário, vá até um ponto que de ((altura do contentView - altura da documentView) * oldVerticalPercentage) estabelece o documento ". Eixo X é claro similar.

Além disso, eu tenho quase certeza que você não precisa de uma chamada para -display aqui, e, em geral, não deve nunca chamam, nunca. (-SetNeedsDisplay:. No máximo)

-Wil

Outras dicas

Me acha que você gostaria de escrever demais ...; -)

// 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);

Esta é uma questão de idade, mas espero que alguém olhando para este encontra a minha resposta útil ...

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];
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top