OK, je pense qu'il est temps de faire une place officielle sur Internet pour ce problème: Comment faire un UIScrollView
photoviewer avec pagination et zoom. Bienvenue mes collègues UIScrollView
hackers.
J'ai un UIScrollView
avec la pagination activée et j'affiche UIImageViews
comme l'application de photos intégrée. (Est-ce que cela vous semble familier?)
J'ai trouvé le projet suivant sur github:
https://github.com/andreyvit/ScrollingMadness/wiki
Ce qui montre comment implémenter le zoom dans une vue de défilement lorsque la pagination est activée. Si quelqu'un d'autre essaie cela, j'ai en fait dû supprimer la sous-classe UIScrollView
et utiliser la classe native sinon cela ne fonctionne pas. Je pense que c'est à cause des changements dans le SDK 3.0 concernant la façon dont la vue de défilement intercepte les événements tactiles.
L'idée est donc de supprimer toutes les autres vues lorsque vous commencez à zoomer et de déplacer la vue actuelle vers (0, 0) dans le scrollview
, en mettant à jour le contentsize
etc. Ensuite, lorsque vous zoomez de retour à 1.0f, il ajoute les autres vues et remet tout en ordre.
Quoi qu'il en soit, ce projet fonctionne parfaitement dans le simulateur, mais sur l'appareil, il y a un mouvement désagréable de la vue que vous redimensionnez, ce qui semble être dû au fait que nous modifions le contentsize
/offset
etc. pour la vue redimensionnée. Vous devez faire cette vue en se déplaçant sinon vous pouvez faire un panoramique vers la gauche à travers l'espace laissé par les autres vues.
J'ai trouvé une note intéressante dans les "Problèmes connus" des Notes de version du SDK 3. :
UIScrollView: après le zoom, l'encart de contenu est ignoré et le contenu est laissé dans la mauvaise position.
Ce genre de son ressemble à ce qui se passe ici. Après avoir zoomé, la vue se déplacera hors écran car vous avez modifié le décalage, etc.
J'ai déjà passé des heures là-dessus et je ralentis pour arriver à la triste prise de conscience que cela ne fonctionnera tout simplement pas.
La visionneuse de photos de Three20 est hors de question: son poids est trop lourd et il y a trop d'interface utilisateur inutile et d'autres comportements.
L'application photo intégrée semble faire de la magie. Si vous effectuez un zoom avant sur une image et effectuez un panoramique sur les bords éloignés, la photo actuelle se déplace indépendamment de la photo à côté, ce qui n'est pas ce que vous obtenez lorsque vous essayez avec un UIScrollView
standard.
J'ai vu des discussions sur l'imbrication des UIScrollView
mais je ne veux vraiment pas y aller.
Quelqu'un at-il réussi cela avec le UIScrollView
standard (et fonctionne dans les SDK 2.2 et 3.0)? Je n'ai pas envie de rouler mon propre zoom + rebond + panoramique + code de pagination.
[~ # ~] mise à jour [~ # ~]
J'ai supprimé ma réponse précédente en raison des nouvelles ci-dessous ...
Grande nouvelle pour ceux qui n'ont pas entendu. Apple a diffusé les vidéos de la session WWDC 2010 à tous les membres du programme pour développeurs iphone. L'un des sujets abordés est de savoir comment ils ont créé l'application photos !!! Ils construisent une application très similaire étape par étape et ont mis à disposition tout le code gratuitement.
Il n'utilise pas non plus d'API privée. Voici un lien vers l'exemple de téléchargement de code. Vous devrez probablement vous connecter pour y accéder.
Et, voici un lien vers la page iTunes WWDC:
J'ai écrit un navigateur photo simple et facile à utiliser appelé MWPhotoBrowser . J'ai décidé de le créer car Three20 était trop lourd/gonflé car tout ce dont j'avais besoin était une visionneuse de photos.
MWPhotoBrowser peut afficher une ou plusieurs images en fournissant soit des objets UIImage, soit des URL vers des fichiers, des images Web ou des ressources de bibliothèque. Le navigateur de photos gère le téléchargement et la mise en cache des photos à partir du Web de manière transparente. Les photos peuvent être agrandies et panoramiques, et des légendes facultatives (personnalisables) peuvent être affichées. Le navigateur peut également être utilisé pour permettre à l'utilisateur de sélectionner une ou plusieurs photos à l'aide de la grille ou de la vue principale de l'image.
Vous dites que vous avez vu des discussions sur l'imbrication d'UIScrollViews mais que vous ne voulez pas y aller - mais c'est la voie à suivre! Cela fonctionne facilement et bien.
C'est essentiellement ce que Apple fait dans son exemple PhotoScroller (et le discours de la WWDC 2010 lié à dans la réponse de Jonah). Seulement dans ces exemples, ils ont ajouté tout un tas de mosaïques complexes et d'autre gestion de la mémoire Si vous n'avez pas besoin de la mosaïque, etc. et si vous ne voulez pas parcourir ces exemples et essayer de supprimer les bits qui y sont liés, le principe sous-jacent d'imbrication d'UIScrollViews est en fait assez simple:
Créez un UIScrollView externe et définissez son pagingEnabled = true. Ajoutez-le à votre vue principale et définissez sa largeur et sa hauteur sur la largeur et la hauteur de votre vue principale.
Créez autant d'UIScrollViews internes que vous le souhaitez d'images. Réglez leur largeur et leur hauteur sur la largeur et la hauteur de votre vue principale. Ajoutez-les en tant que sous-vues à votre UIScrollView externe, les unes à côté des autres, de gauche à droite.
Définissez la taille du contenu de l'UIScrollView externe au total des largeurs de tous les UIScrollViews internes côte à côte (qui est égale à [la largeur de votre vue principale] * [nombre d'images]).
Ajoutez les UIImageViews de vos images aux UIScrollViews internes, une UIImageView à chaque UIScrollView interne. Définissez la taille du contenu de chaque UIScrollView sur la taille de chaque UIImageView.
Définissez les échelles de zoom min et max pour chaque UIScrollView interne et définissez chacun des délégués de l'UIScrollView interne sur votre contrôleur de vue. Dans le viewForZoomingInScrollView du délégué, renvoyez le UIImageView approprié pour le UIScrollView qui est passé. (Pour ce faire, il suffit de conserver chacun des UIImageViews dans un NSArray et de définir la propriété de balise d'UIScrollView correspondante sur l'index du UIImageView approprié. Vous pouvez ensuite lire la balise dans le UIScrollView passé à viewForZoomingInScrollView et renvoyer le UIImageView approprié du NSArray) .
C'est ça. Fonctionne comme l'application photo.
Si vous avez beaucoup de photos, pour économiser de la mémoire, vous pouvez simplement avoir deux UIScrollViews internes et deux UIImagesViews. Vous basculez ensuite dynamiquement entre eux, en déplaçant leur position dans le UIScrollView externe et en modifiant leurs images lorsque l'utilisateur fait défiler le UIScrollView externe. C'est un peu plus complexe mais le même principe.
J'ai joué avec l'application native Photos, et je pense pouvoir dire en toute confiance qu'ils utilisent un seul UIScrollView. Le cadeau est le suivant: zoomez sur une image et tirez vers la gauche ou la droite. Vous verrez la photo suivante ou précédente. Si vous tirez assez fort, il passera même à la page suivante avec un zoom de 1,0f. Retournez en arrière et la photo précédemment agrandie sera également de retour au zoom 1.0f.
Visiblement, je n'ai pas écrit Photos.app, mais je vais deviner comment ils l'ont fait:
scrollViewDidScroll:
viewForZoomingInScrollView:
scrollViewDidEndZooming:withView:atScale:
et éventuellement faire un anti-aliasing, etc basé sur le contenuSi vous décidez de l'essayer, faites-moi savoir comment cela fonctionne pour vous. J'adorerais savoir comment vous vous retrouvez finalement avec ça. Encore mieux, postez-le sur github.
J'ai joué avec l'application native Photos, et je pense pouvoir dire en toute confiance qu'ils utilisent un seul UIScrollView. Le cadeau est le suivant: zoomez sur une image et tirez vers la gauche ou la droite. Vous verrez la photo suivante ou précédente. Si vous tirez assez fort, il passera même à la page suivante avec un zoom de 1,0f. Retournez en arrière et la photo précédemment agrandie sera également de retour au zoom 1.0f.
C'est faux. J'utilise des vues de défilement imbriquées et j'obtiens exactement le même effet. Si vous utilisez un schéma de gestion de la mémoire (que j'ai dû commencer à utiliser ... mon numéro de page est assez élevé (environ 50 chacun en 2 scrollViews)), alors vous pouvez utiliser un mécanisme similaire à ce que vous avez déclenché votre page charge/décharge pour déclencher une réinitialisation du zoom pour les pages -1 et +1 à partir de la page actuelle.
Je soupçonne que Apple déclenche cela dès que l'image précédente a disparu.
Ce que je ne comprends pas, c'est comment réaliser un défilement fluide entre les pages - il y a toujours un blocage très court au moment de la transition. Ne le prends pas. Je suis devenu assez profond pour le réparer - NSInvocationOperations était mon premier arrêt, puis j'ai créé une file d'attente de vues réutilisables pour les pages vues (qui conservent leurs vues d'image) ... toujours ce blocage duré.
Je n'ai qu'une seule NSOperationQueue en cours d'exécution et j'ai essayé de jouer avec le nombre maximum d'opérations simultanées. Ma pensée était que le fil principal était obstrué par des files d'attente concurrentes, ou peut-être même une file d'attente essayant de faire trop ...
J'ai même essayé de créer des versions de très faible qualité de mes médias, au cas où c'était le problème. Avec chaque image pesant à environ 10k (ce sont des jpeg, faites attention) ... vous l'avez deviné. Le blocage est toujours là.
Je suis pratiquement résolu à faire ce que j'ai fait auparavant et à utiliser TTPhotoViewController de Three20. J'ai passé quelques heures à parcourir ce code, et c'est toujours une excellente éducation. À ce stade, cependant, j'aimerais vraiment savoir d'où vient ce blocage, ne serait-ce que pour que je puisse passer mes heures de sommeil à me demander quelque chose de moins bouillonnant.
ce serait bien si Apple a construit une visionneuse d'images comme l'application photos dans le SDK pour que nous l'utilisions. J'utilise actuellement three20 et cela fonctionne très bien. Mais c'est beaucoup de choses supplémentaires à emporter quand tout ce que vous voulez vraiment, c'est la visionneuse de photos.
j'écris un code pour ça, et peut être comme référence
charger la vue actuelle scrollview et imageview .. et pour l'écran à côté de la vue actuelle, seulement imageview
supprimer toute vue lors du chargement de la page actuelle pour économiser de la mémoire, donc bon pour de nombreux projets photo
utiliser une balise pour différencier les différentes vues de défilement
_xxxxxxx