Dans iOS 13, il y a un nouveau comportement pour le contrôleur de vue modale lors de sa présentation, et j'ai trouvé que l'application intégrée Photo présente un contrôleur de vue de modèle plus petit.
Comment puis-je présenter un viewController avec une taille personnalisée comme celle-ci can et peut glisser jusqu'à une plus grande hauteur?
Captures d'écran de l'application photo système.
Répondre en Swift
Je cherchais un moyen de reproduire ce type de comportement de ViewController, bien qu'avec une interface utilisateur de base, et j'ai trouvé une solution assez simple. Fondamentalement, vous créez un ViewController (CardViewContoller
) avec un arrière-plan transparent, puis vous y ajoutez une vue semblable à une carte avec un UIPanGestureReconizer
, qui vous permettra de le faire glisser et de le supprimer avec le ViewController.
Pour vous présenter, appelez simplement present
, en définissant modalPresentationStyle
sur .overCurrentContext
Et modalTransitionStyle
sur .coverVertical
:
let cardVC = CardViewController()
cardVC.modalPresentationStyle = .overCurrentContext
cardVC.modalTransitionStyle = .coverVertical
present(cardVC, animated: true, completion: nil)
Dans CardViewController
, qui peut être créé par programmation ou à l'aide d'Interface Builder, vous ajoutez un UIPanGestureRecognizer
à votre vue de carte (contentView
):
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handleDismiss(recognizer:)))
panGestureRecognizer.cancelsTouchesInView = false
contentView.addGestureRecognizer(panGestureRecognizer)
Ensuite, ajoutez simplement une fonction @objc
Qui répondra à UIPanGestureRecognizer:
@objc
func handleDismiss (recognizer: UIPanGestureRecognizer) {
switch recognizer.state {
case .changed:
viewTranslation = recognizer.translation(in: view)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
guard self.viewTranslation.y > 0 else {return}
self.view.transform = CGAffineTransform(translationX: 0, y: self.viewTranslation.y)
})
case .ended:
if viewTranslation.y < swipeThreshold {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.view.transform = .identity
})
} else {
dismiss(animated: true, completion: nil)
}
default:
break
}
}
swipeThreshold
est une variable CGFloat
avec une valeur de votre choix (200 fonctionne très bien pour moi), que si la traduction UIPanGestureRecognizer
y dépasse, cela déclenchera le rejet du ViewController avec tous les éléments. De même, vous pouvez ajouter un simple bouton qui fermera le ViewController lors de l'appel de .touchUpInside
dismiss()
Si vous le souhaitez, vous pouvez consulter ce dépôt , dans lequel j'ai un exemple de projet qui présente ce comportement. De cette façon, vous pouvez créer vos propres cartes totalement personnalisables.
Je ne pense pas que cela soit possible avec l'implémentation UIViewController standard - c'est-à-dire simplement en définissant une hauteur de présentation, même avec le nouveau style de présentation d'iOS 13.
Vous voudrez peut-être étudier une solution tierce (ou vous en inspirer) comme ceci: