Quelqu'un peut-il me dire comment imiter la feuille inférieure dans la nouvelle application Maps dans iOS 10?
Dans Android, vous pouvez utiliser un BottomSheet
qui imite ce comportement, mais je n'ai rien trouvé de tel pour iOS.
Est-ce une simple vue de défilement avec un encart de contenu, de sorte que la barre de recherche se trouve en bas?
Je suis assez nouveau dans la programmation iOS, donc si quelqu'un pouvait m'aider à créer cette mise en page, ce serait très apprécié.
Voici ce que j'entends par «feuille de fond»:
Réponses:
Je ne sais pas exactement comment la feuille inférieure de la nouvelle application Maps répond aux interactions des utilisateurs. Mais vous pouvez créer une vue personnalisée qui ressemble à celle des captures d'écran et l'ajouter à la vue principale.
Je suppose que vous savez comment:
1- créer des contrôleurs de vue soit par story-boards soit en utilisant des fichiers xib.
2- Utilisez googleMaps ou MapKit d'Apple.
Exemple
1- Créez 2 contrôleurs de vue, par exemple, MapViewController et BottomSheetViewController . Le premier contrôleur hébergera la carte et le second est la feuille inférieure elle-même.
Configurer MapViewController
Créez une méthode pour ajouter la vue de feuille inférieure.
Et appelez-le dans la méthode viewDidAppear:
Configurer BottomSheetViewController
1) Préparez le fond
Créez une méthode pour ajouter des effets de flou et d'éclat
appeler cette méthode dans votre vueWillAppear
Assurez-vous que la couleur d'arrière-plan de la vue de votre contrôleur est clearColor.
2) Animer l'apparence de la feuille de fond
3) Modifiez votre xib comme vous le souhaitez.
4) Ajoutez Pan Gesture Recognizer à votre vue.
Dans votre méthode viewDidLoad, ajoutez UIPanGestureRecognizer.
Et implémentez votre comportement gestuel:
Feuille inférieure défilante:
Si votre vue personnalisée est une vue de défilement ou toute autre vue héritée de, vous avez donc deux options:
Première:
Concevez la vue avec une vue d'en-tête et ajoutez le panGesture à l'en-tête. (mauvaise expérience utilisateur) .
Seconde:
1 - Ajoutez le panGesture à la vue de feuille inférieure.
2 - Implémentez UIGestureRecognizerDelegate et définissez le délégué panGesture sur le contrôleur.
3- Implémentez shouldRecognizeSimultaneousWith avec la fonction déléguée et désactivez la propriété scrollView isScrollEnabled dans deux cas:
Sinon, activez le défilement.
REMARQUE
Dans le cas où vous définissez .allowUserInteraction comme une option d'animation, comme dans l'exemple de projet, vous devez donc activer le défilement à la fermeture de la fin de l'animation si l'utilisateur fait défiler vers le haut.
Exemple de projet
J'ai créé un exemple de projet avec plus d'options sur ce dépôt qui peut vous donner de meilleures informations sur la façon de personnaliser le flux.
Dans la démo, la fonction addBottomSheetView () contrôle quelle vue doit être utilisée comme feuille inférieure.
Exemples de captures d'écran du projet
- Vue partielle
- Vue complète
- Vue déroulante
la source
J'ai publié une bibliothèque basée sur ma réponse ci-dessous.
Il imite la superposition d'application des raccourcis. Consultez cet article pour plus de détails.
Le composant principal de la bibliothèque est le
OverlayContainerViewController
. Il définit une zone dans laquelle un contrôleur de vue peut être déplacé de haut en bas, masquant ou révélant le contenu en dessous.Mettre
OverlayContainerViewControllerDelegate
en œuvre pour spécifier le nombre d'encoches souhaité:Réponse précédente
Je pense qu'il y a un point important qui n'est pas traité dans les solutions proposées: la transition entre le parchemin et la traduction.
Dans Maps, comme vous l'avez peut-être remarqué, lorsque la tableView atteint
contentOffset.y == 0
, la feuille inférieure glisse vers le haut ou vers le bas.Le point est délicat car nous ne pouvons pas simplement activer / désactiver le défilement lorsque notre geste de panoramique commence la traduction. Cela arrêterait le défilement jusqu'à ce qu'une nouvelle touche commence. C'est le cas dans la plupart des solutions proposées ici.
Voici mon essai de mettre en oeuvre cette motion.
Point de départ: l'application Maps
Pour commencer notre enquête, nous allons visualiser la hiérarchie de la vue des cartes (début Maps sur un simulateur et sélectionnez
Debug
>Attach to process by PID or Name
>Maps
dans Xcode 9).Cela ne dit pas comment fonctionne la motion, mais cela m'a aidé à en comprendre la logique. Vous pouvez jouer avec le lldb et le débogueur de hiérarchie de vues.
Nos piles de contrôleur de vue
Créons une version de base de l'architecture Maps ViewController.
Nous commençons par un
BackgroundViewController
(notre vue de la carte):Nous mettons la tableView dans un espace dédié
UIViewController
:Maintenant, nous avons besoin d'un VC pour intégrer la superposition et gérer sa traduction. Pour simplifier le problème, nous considérons qu'il peut traduire la superposition d'un point statique
OverlayPosition.maximum
à un autreOverlayPosition.minimum
.Pour l'instant, il n'a qu'une seule méthode publique pour animer le changement de position et il a une vue transparente:
Enfin, nous avons besoin d'un ViewController pour intégrer le tout:
Dans notre AppDelegate, notre séquence de démarrage ressemble à:
La difficulté derrière la traduction de superposition
Maintenant, comment traduire notre superposition?
La plupart des solutions proposées utilisent un outil de reconnaissance des mouvements panoramiques dédié, mais nous en avons déjà un: le mouvement panoramique de la vue tableau. De plus, nous devons garder le défilement et la traduction synchronisés et
UIScrollViewDelegate
tous les événements dont nous avons besoin!Une implémentation naïve utiliserait un deuxième mouvement panoramique et tenterait de réinitialiser la vue
contentOffset
de la table lorsque la traduction se produit:Mais ça ne marche pas. La tableView met à jour son
contentOffset
lorsque sa propre action de reconnaissance de mouvement panoramique se déclenche ou lorsque son rappel displayLink est appelé. Il n'y a aucune chance que notre module de reconnaissance se déclenche juste après ceux pour réussir à remplacer lecontentOffset
. Notre seule chance est soit de participer à la phase de mise en page (en remplaçantlayoutSubviews
les appels de la vue de défilement à chaque image de la vue de défilement), soit de répondre à ladidScroll
méthode du délégué appelé à chaquecontentOffset
modification de la. Essayons celui-ci.L'implémentation de la traduction
Nous ajoutons un délégué à notre
OverlayVC
pour envoyer les événements de scrollview à notre gestionnaire de traduction, leOverlayContainerViewController
:Dans notre conteneur, nous suivons la traduction à l'aide d'une énumération:
Le calcul de la position actuelle ressemble à ceci:
Nous avons besoin de 3 méthodes pour gérer la traduction:
Le premier nous indique si nous devons commencer la traduction.
Le second effectue la traduction. Il utilise la
translation(in:)
méthode du mouvement panoramique du scrollView.Le troisième anime la fin de la traduction lorsque l'utilisateur relâche son doigt. Nous calculons la position en utilisant la vitesse et la position actuelle de la vue.
L'implémentation des délégués de notre superposition ressemble simplement à:
Dernier problème: répartir les touches du conteneur de superposition
La traduction est maintenant assez efficace. Mais il y a encore un dernier problème: les touches ne sont pas apportées à notre vue d'arrière-plan. Ils sont tous interceptés par la vue du conteneur de superposition. Nous ne pouvons pas mettre
isUserInteractionEnabled
àfalse
parce qu'il désactiverait aussi l'interaction dans notre présentation de tableau. La solution est celle qui est utilisée massivement dans l'application Maps,PassThroughView
:Il se supprime de la chaîne répondeur.
Dans
OverlayContainerViewController
:Résultat
Voici le résultat:
Vous pouvez trouver le code ici .
S'il vous plaît, si vous voyez des bugs, faites le moi savoir! Notez que votre implémentation peut bien sûr utiliser un deuxième geste de panoramique, spécialement si vous ajoutez un en-tête dans votre superposition.
Mise à jour 23/08/18
Nous pouvons remplacer
scrollViewDidEndDragging
parwillEndScrollingWithVelocity
plutôt queenabling
/disabling
le défilement lorsque l'utilisateur termine de glisser:Nous pouvons utiliser une animation de ressort et permettre l'interaction de l'utilisateur pendant l'animation pour améliorer le flux de mouvement:
la source
UIViewPropertyAnimator
(qui a la capacité de faire une pause), puis utilisez lafractionComplete
propriété pour effectuer le gommage.translateView(following:)
méthode, vous calculez la hauteur en fonction de la traduction, mais cela peut commencer à partir d'une valeur différente de 0,0 (par exemple, la vue de la table défile un peu et la superposition est maximisée lorsque vous commencez à faire glisser) . Cela entraînerait le saut initial. Vous pouvez résoudre ce problème par lescrollViewWillBeginDragging
rappel où vous vous souviendrez de l'initialecontentOffset
de la vue de table et l'utiliserez dans letranslateView(following:)
calcul de.csrutil disable && reboot
. Vous aurez alors tous les pouvoirs que root devrait normalement vous donner, y compris la possibilité de vous attacher à un processus Apple.Essayez Poulie :
https://github.com/52inc/Pulley
la source
Vous pouvez essayer ma réponse https://github.com/SCENEE/FloatingPanel . Il fournit un contrôleur de vue de conteneur pour afficher une interface "feuille de fond".
Il est facile à utiliser et cela ne vous dérange pas de la manipulation de reconnaissance de gestes! Vous pouvez également suivre une vue de défilement (ou la vue frère) dans une feuille inférieure si nécessaire.
Ceci est un exemple simple. Veuillez noter que vous devez préparer un contrôleur de vue pour afficher votre contenu dans une feuille inférieure.
Voici un autre exemple de code pour afficher une feuille inférieure pour rechercher un emplacement comme Apple Maps.
la source
J'ai écrit ma propre bibliothèque pour obtenir le comportement souhaité dans l'application ios Maps. Il s'agit d'une solution orientée protocole. Vous n'avez donc pas besoin d'hériter d'une classe de base à la place, créez un contrôleur de feuille et configurez comme vous le souhaitez. Il prend également en charge la navigation / présentation interne avec ou sans UINavigationController.
Voir le lien ci-dessous pour plus de détails.
https://github.com/OfTheWolf/UBottomSheet
la source
J'ai récemment créé un composant appelé
SwipeableView
sous-classe deUIView
, écrit en Swift 5.1. Il prend en charge les 4 directions, dispose de plusieurs options de personnalisation et peut animer et interpoler différents attributs et éléments (tels que les contraintes de mise en page, la couleur d'arrière-plan / de teinte, la transformation affine, le canal alpha et le centre de vue, tous démontrés avec la vitrine respective). Il prend également en charge la coordination de balayage avec la vue de défilement interne si elle est définie ou détectée automatiquement. Devrait être assez facile et simple à utiliser (j'espère 🙂)Lien sur https://github.com/LucaIaco/SwipeableView
preuve de concept:
J'espère que ça aide
la source
Vous pouvez peut-être essayer ma réponse https://github.com/AnYuan/AYPannel , inspirée de Pulley. Transition en douceur du déplacement du tiroir au défilement de la liste. J'ai ajouté un geste de panoramique sur la vue de défilement du conteneur et j'ai défini shouldRecognizeSimultaneousWithGestureRecognizer pour retourner YES. Plus de détails dans mon lien github ci-dessus. Je souhaite aider.
la source