9
votes

Défilement indésirable lors de l'animation de zoomscale dans UiscrollView

Résumé exécutif: Durée UISCrollView fait une modification non désirée à la valeur de contentoffset , entraînant ainsi l'application pour afficher le mauvais emplacement dans le document vu. Le changement indésirable se produit conjointement à une modification animée de la vue Zoomscale .

les détails: J'ai des problèmes lors du zoomez avec catiledlayer dans un uiscrollview . Le catiledlayer contient un PDF et lorsque contentoffset est dans une certaine plage, lorsque je zoomer, le contentoffset est modifié (c'est le bogue) avant que le zoom se produise. Le contentoffset semble être modifié dans le code d'Apple.

Pour illustrer le problème, j'ai modifié l'exemple d'exemple d'Apple, ZoomingPDFViewer. Le code est sur GitHub: https://github.com/dirkmaas/zoomingpdfviewer-bug

Un robinet causera zoomscale pour être modifié à 0,5, en utilisant animatewithduration , zoomez donc. Si le UiscrollView 'S contentoffset.y est inférieur à environ 2700 ou supérieur à 5900, le ZoomScale L'animation fonctionne bien. Si le robinet se produit lorsque contentoffset.y est entre ces deux valeurs, le contentoffset.y sautera (non animé) à environ 2700, puis le zoomscale < / Code> L'animation se produira, mais le défilement se produira en même temps, de sorte que lorsque l'animation est terminée, le contentoffset.y est l'endroit où il devrait être. Mais d'où vient le saut?

Par exemple, dites le contentoffset.y est 2000 lorsque l'écran est taraudé: le zoomscale L'animation fonctionne tout à fait; contentoffset.y n'est pas modifié.

Mais si le contentoffset.y est 4000 lorsque l'écran est taraudé: le contentoffset.y sautera, sans animation, à environ 2700, puis zoomer et faire défiler va commencer à partir de ce point et se produire en même temps. Lorsque l'animation est terminée, il semble que nous ayons zoomé directement à partir de 4000, nous nous retrouvons donc au bon endroit, mais le comportement est faux.

une note sur l'interface utilisateur:

  • Le texte peut être défilé verticalement de la manière normale
  • Le texte peut être zoomé dans et à l'extérieur en pinçant de la manière normale
  • Un seul robinet provoquera la définition du zoomscale à 0,5; Le changement est animé

    J'ai remarqué que si zoomscale est supérieur à 0,5, le saut n'est pas si gros. Également, si j'utilise setzoomscale: animé: au lieu de animatewithduration , le bogue disparaît, mais je ne peux pas l'utiliser parce que j'ai besoin de chaîner des animations.

    Voici un résumé de ce que j'ai fait (le code dans GitHub inclut ces changements):

    • téléchargé zoomingpdfviewer de http://developer.apple.com/library/ios/ # Samplecode / ZoomingPDFviewer / Introduction / Intro.html et l'a ouvert en Xcode
    • Modification des paramètres de construction | Architectures | Base SDK aux derniers iOS (iOS 4.3) Modification des paramètres de construction | GCC 4.2 - Langue | Compiler des sources quant à Objective-C ++
    • supprimé TestPage.pdf du projet
    • ajouté "WhoIAM 5 24 Cropped 3-2.PDF" au projet à sa place
    • ajouté pdfscrollview * ScrollView; à zoomingpdfviewervieflontroller Classe
    • modifié loadview in zoomingpdfvievieviewcontroller Pour initialiser ScrollView au lieu de SV
    • ajouté ViewDiDload , HandletApfrom: reconnaître et zoomout à zoomingpdfviewerviewontroller dans pdfscrollview.m
    • commenté ScrollViefDidDendZooming: Avec vue: ATSCALE et ScrollviewWillBeGinzoom: Parce qu'ils font des trucs dans l'arrière-plan d'image qui distrait du problème de la question

      Merci beaucoup pour avoir porté avec moi, et n'importe quelle aide!


2 commentaires

Qu'entendez-vous en ayant besoin de chaîner des animations? Pourquoi ne pouvez-vous pas utiliser ScrollViefDidIdendZoom


@Michael Frederick - Bon point. C'est un travail autour, mais j'aime utiliser animatewithduration: au lieu de setzoomscale: animé: car, sauf si je manque quelque chose, ce dernier ne permet pas de contrôler la durée de la durée , et parce que les animations de bloc font un meilleur travail, à mon avis, de garder le code associé ensemble. Plus Apple semble nous encourager à utiliser des animations de blocs. Donc, peut-être que j'aurais dû dire "Je ne veux pas utiliser setzoomscale: animé: ." Merci pour le commentaire!


5 Réponses :


8
votes

Une des choses les plus difficiles à comprendre sur le zoom est qu'il arrive toujours autour d'un point appelé point d'ancrage. Je pense que la meilleure façon de comprendre est d'imaginer un système de coordonnées superposé sur un autre. Say A est votre système de coordonnées externe, B est l'intérieur (B sera le ScrollView). Lorsque le décalage de B est (0,0) et la balance est de 1,0, le point B (0,0) correspond à un (0,0) et dans le général B (x, y) = A (x, y) = ).

En outre, si le décalage de B est (XOFF, YOFF) puis B (x, y) = A (x - xoff, y-yoff). Encore une fois, cela suppose toujours que l'échelle de zoom est de 1,0.

Maintenant, laissez le décalage être à nouveau (0,0) à nouveau et imaginez ce qui se passe lorsque vous essayez de zoomer. Il doit y avoir un point sur l'écran qui ne bouge pas lorsque vous zoomez et que tout autre point se déplace vers l'extérieur de ce point. C'est ce que définit le point d'ancrage. Si votre ancre est (0,0), le point de gauche reste fixé lorsque tous les autres points progressent et à droite. Dans ce cas, le décalage reste le même.

si votre point d'ancrage est (0,5, 0,5) (le point d'ancrage est normalisé, c'est-à-dire 0 à 1, de sorte que 0,5 est à mi-parcours), alors le point central reste corrigé pendant que tous les autres points se déplacent vers l'extérieur. Cela signifie que le décalage doit changer pour refléter cela. Si c'est sur un iPhone en mode portrait et que vous zoomez à l'échelle 2.0, la valeur de point d'ancrage X déplacera la moitié de la largeur de l'écran, 320/2 = 160.

La position réelle du contenu Vues de défilement L'écran est défini à la fois par le décalage et le point d'ancrage. Donc, si vous modifiez simplement le point d'ancrage de calques en dessous sans effectuer une modification correspondante au décalage, vous verrez que la vue apparaît pour passer à un emplacement différent, même si le décalage est identique.

Je suis Devinez que c'est le problème sous-jacent ici. Lorsque vous animez le zoom, l'animation de base doit choisir un nouveau point d'ancrage afin que le zoom "semble" correct. Cela modifiera également le décalage afin que la région visible vise la région visible à l'écran ne saute pas. Essayez de vous connecter à l'emplacement du point d'ancrage à différents moments tout au long de ce processus (il est défini sur la calayeuse sous-jacente de n'importe quelle vue que vous accédez à une propriété Vues "Couche").

aussi, veuillez consulter la documentation ici pour de jolies images et probablement Une meilleure meilleure description de la situation que celle que j'ai donnée ici :)

Enfin, voici un extrait de code que j'ai utilisé dans une application pour modifier le point d'ancrage d'une couche sans passer à l'écran. < / p> xxx


1 commentaires

Merci, mais je ne pense pas que c'était ça. Le code n'essaie pas de changer la valeur anchorpoint directement ou indirectement, et je l'ai enregistré avant et après le zoom, et les deux fois, il s'agissait de la valeur par défaut (0,5, 0.5). De plus, par sa nature, anchorpoint est toujours à l'écran, visible, ce qui signifie que tout saut serait inférieur à 1 écran de l'écran, mais le saut que je vois des causes contentoffset.y < / Code> Pour changer de milliers - plusieurs écrans loin. Pour moi, cela prouve que AnchorPoint n'est pas le problème, à moins que je sois mal compris quelque chose.



2
votes

Vous devez utiliser ScrollViewDidLendZoom Sinon, je pense que vous devrez supprimer l'utilisation de la propriété ZoomScale de l'UISCrollView et implémentera plutôt du zoomer complètement manuellement, par ex. http://jonathanwatmough.com/ 2008/12 / Mise en œuvre-Tap-To-Zoom-in-Uiscrollview-On-an-iPhone / .


0 commentaires

2
votes

J'avais de nombreux bugs avec zoomer lorsque ma fonction de visualisationForzoomingScrollViewsCrollview retourne directement à ScrollView.

Beaucoup de ces comportements étranges ont disparu après avoir défini une vue à l'intérieur de la vue ScrollView qui contenant tout et le renvoie dans le point de vue de la vueForzoomingScrollView. Peut-être que cela devrait résoudre votre problème aussi: P>

-(void) someIntializationFunction {
    [myScrollView addSubView:self.globalContainer];
    // Now had everything in the container and not in the scrollView directly
    ....
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView; {
    return self.globalContainer;
}


0 commentaires

3
votes

Je joue avec le code que vous avez posté et je pense avoir trouvé ce qui se passe. Lorsque vous faites une animation de bloc comme dans votre code:

[UIView animateWithDuration:4.0
                 animations:^ {
                     self.scrollView.zoomScale = 0.5;
                 }
                 completion:nil];


0 commentaires

0
votes

Je pense que vous devez manipuler le contentInset et / ou le contentoffset vous-même, sur chaque événement de défilement. Manipuler les points d'ancrage ne vous aideront pas. Regarde Cette question et ma réponse.


0 commentaires