Pregunta

Tengo una NSView (myView) envuelto en una NSScrollView (myScrollView). El uso del zoom-en los botones de entrada / salida, el usuario puede modificar la escala de myView. Si el usuario se desplaza actualmente a un punto particular en myView, me gustaría mantener esa parte de la vista en la pantalla después de que el zoom ha tenido lugar.

Tengo código que se parece a esto:

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

Y parece una especie de cerca, pero no es del todo bien y no puedo averiguar lo que estoy haciendo mal. Mis dos preguntas son:

1) ¿No hay un sistema incorporado en algo en la línea de:

   [myView adjustScaleBy: 0.5 whilePreservingLocationInScrollview:myScrollView];

2) Si no es así, ¿alguien puede ver lo que estoy haciendo mal en mi "camino largo" enfoque, por encima?

Gracias!

¿Fue útil?

Solución

Mantener la misma posición de desplazamiento después de la escala no es fácil. Una cosa que hay que decidir es qué quiere decir con "el mismo" - ¿Quieres que la parte superior, media o inferior del área visible antes de escalar a permanecer en el lugar después de escalar

?

O, de forma más intuitiva, qué quiere la posición que se mantiene en su lugar un porcentaje por el rect visibles igual al porcentaje que se desplazan hacia abajo el documento cuando se inicia (por ejemplo, por lo que el centro del dedo pulgar del desplazador no lo hace desplazarse hacia arriba o hacia abajo durante una escala, el pulgar apenas crece o se reduce).

Si desea que el último efecto, una forma de hacerlo es conseguir verticalScroller y horizontalScroller del NSScrollView y, a continuación, lea su 'floatValue de. Estos son normalizado de 0 a 1, donde '0' significa que está en la parte superior del documento y 1 significa que está al final. Lo bueno de pedir el desplazador de esto es que si el documento es más corto que el NSScrollView, el desplazador todavía devuelve una respuesta sana en todos los casos para 'floatValue,' por lo que no tiene que especial de los casos esto.

Después de cambiar el tamaño, ajustar la posición de desplazamiento del NSScrollView ser el mismo porcentaje que era antes de la escala - pero, por desgracia, aquí es donde me agito mis manos un poco. No he hecho esto desde hace tiempo en mi código, pero por lo que recuerdo que no puedo acaba de establecer las NSScrollers' 'de floatValue directamente -. Se van a ver desplazan, pero no van a afectar a la realidad NSScrollView

Por lo tanto, usted tiene que escribir un poco de matemática para calcular el nuevo punto superior izquierdo de su documento basado en el porcentaje que desea ser a través de él - en el eje y, por ejemplo, se verá como " Si el documento es ahora más corto que contentView del ScrollView, vaya al punto 0, de lo contrario desplazarse hasta un punto que es ((altura de contentView - altura de DocumentView) * oldVerticalPercentage) hacia abajo el documento ". eje X es, por supuesto similar.

Además, estoy casi seguro de que no es necesario un llamado a -display aquí, y en general no debe jamás llamarlo, nunca. (-SetNeedsDisplay:. En la mayoría)

-Wil

Otros consejos

Me piensa que usted tiene gusto de escribir demasiado ...; -)

// 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 es una vieja pregunta, pero espero que alguien que busca este encuentra mi respuesta ú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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top