Comment maintenir la position de défilement dans NSScrollView lors du changement de l'échelle?

StackOverflow https://stackoverflow.com/questions/1296920

Question

J'ai un NSView (myView) enveloppé dans un NSScrollView (myScrollView). Utilisation des boutons de zoom in / out, l'utilisateur peut modifier l'échelle de myView. Si l'utilisateur est défilée à un endroit particulier dans myView, je voudrais garder cette partie de la vue à l'écran après le zoom a eu lieu.

J'ai eu un code qui ressemble à ceci:

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

Et il semble sorte de près, mais pas tout à fait raison et je ne peux pas comprendre ce que je fais mal. Mes deux questions sont:

1) est-il pas quelque chose le long des lignes de intégrée:

   [myView adjustScaleBy: 0.5 whilePreservingLocationInScrollview:myScrollView];

2) Dans le cas contraire, peut-on voir ce que je fais mal dans mon approche « long chemin autour » ci-dessus?

Merci!

Était-ce utile?

La solution

Garder la même position de défilement après mise à l'échelle est pas facile. Une chose que vous devez décider est ce que vous entendez par « la même chose » - voulez-vous en haut, au milieu ou en bas de la zone visible avant mise à l'échelle de rester en place après mise à l'échelle

?

Ou, de manière plus intuitive, ne voulez-vous la position qui reste en place un pourcentage sur le rect visible égal au pourcentage que vous défiler vers le bas le document lorsque vous démarrez (par exemple, de sorte que le centre du pouce de la barre de défilement ne déplacer vers le haut ou vers le bas au cours d'une échelle, le pouce pousse tout ou rétrécit).

Si vous voulez que le dernier effet, une façon de le faire est d'obtenir verticalScroller et horizontalScroller, puis lire leur « floatValue du NSScrollView de. Ceux-ci sont normalisées de 0 à 1, où « 0 » signifie que vous êtes en haut du document et 1 signifie que vous êtes à la fin. La bonne chose à demander à la barre de défilement est que si le document est plus court que le NSScrollView, la barre de défilement retourne encore une réponse saine d'esprit dans tous les cas pour « floatValue, » de sorte que vous n'avez pas à ce cas particulier.

Une fois que vous redimensionnez, réglez la position de défilement de la NSScrollView être le même pourcentage qu'il était avant l'échelle - mais, malheureusement, voici où je vague mes mains un peu. Je ne l'ai pas fait dans un certain temps dans mon code, mais je me souviens que vous ne pouvez pas définir les NSScrollers de « floatValue directement -. Ils vont chercher défiler, mais ils ne seront pas réellement affecter la NSScrollView

Alors, vous devrez écrire quelques calculs pour calculer le nouveau point haut à gauche dans votre document en fonction du pourcentage que vous voulez être à travers elle - sur l'axe y, par exemple, ça va ressembler, " Si le document est maintenant plus courte que contentView du ScrollView, faites défiler jusqu'à point 0, faites défiler autrement à un point qui est ((hauteur de contentView - hauteur de DocumentView) * oldVerticalPercentage) vers le bas du document « . axe X est évidemment similaire.

En outre, je suis presque vous n'avez pas besoin d'un appel à -display ici, et en général ne devrait jamais l'appeler, jamais. (-SetNeedsDisplay:. Au plus)

-Wil

Autres conseils

Me pense que vous voulez taper trop ...; -)

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

Ceci est une vieille question, mais j'espère que quelqu'un qui cherche ce trouve ma réponse utile ...

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];
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top