649 votes

Présentation de la modale en plein écran sous iOS 13

Dans iOS 13, il y a un nouveau comportement pour le contrôleur de vue modal lorsqu'il est présenté.

Maintenant, il n'y a pas de plein écran par défaut et lorsque j'essaie de glisser vers le bas, l'application rejette automatiquement le contrôleur de vue.

Comment puis-je empêcher ce comportement et revenir à l'ancien vc modal plein écran ?

modal behaviour

Gracias

839voto

pakizip Points 84

Avec iOS 13, comme indiqué dans la Plateformes État de l'Union Lors de la WWDC 2019, Apple a introduit une nouvelle présentation des cartes par défaut. Afin de forcer le plein écran, vous devez le spécifier explicitement avec :

let vc = UIViewController()
vc.modalPresentationStyle = .fullScreen //or .overFullScreen for transparency
self.present(vc, animated: true, completion: nil)

90 votes

Je dirais que ça ne restera pas longtemps comme défaut. Le site fullScreen devrait être par défaut pour éviter de casser les changements d'interface utilisateur.

19 votes

Je ne compterai pas là-dessus. Dans le passé, Apple a souvent modifié les valeurs par défaut qui ne deviennent actives qu'une fois que vous établissez une liaison avec le SDK actuel. Nous allons Avec un peu de chance, obtenir l'ancien comportement lors de la liaison avec les versions précédentes.

11 votes

Je peux confirmer que les applications créées par Xcode-10 et exécutées sur le simulateur iOS 13 fonctionnent toujours en plein écran par défaut. Comme @DrMickeyLauer l'a dit, construire avec Xcode 11 permet à l'application d'adopter le nouveau comportement. Utilisez isModalInPresentation pour empêcher le geste de balayage d'être rejeté. Voir mon article de blog pour plus de détails : medium.com/@hacknicity/

252voto

Alessandro Points 34

J'ajoute une information qui pourrait être utile à quelqu'un. Si vous avez un enchaînement de storyboard, pour revenir à l'ancien style, vous devez définir l'attribut genre à la propriété Présenter modérément et le Présentation à la propriété Plein écran .

enter image description here

3 votes

Existe-t-il un moyen de définir isModalInPresentation dans Interface Builder ?

0 votes

Vous venez de résoudre mon problème, merci ! 3 jours de bricolage...

130voto

davidbates Points 1612

J'ai eu ce problème sur la vue initiale juste après l'écran de lancement. La solution pour moi, puisque je n'avais pas de transition ou de logique définie, a été de faire passer la présentation d'automatique à plein écran, comme indiqué ici :

fix_storyboard_presentation_default_behavior

2 votes

Existe-t-il un moyen de faire cela de manière programmatique pour toutes les vues au lieu de le faire une par une via le storyboard ?

1 votes

@ShobhitPuri Jetez un coup d'œil à la première solution d'Omreyh ici. stackoverflow.com/a/58255416/4323101

1 votes

Wow, c'était LA réponse à mes problèmes. Merci pour le conseil ! Pour tous ceux qui cherchent à résoudre ce problème, voici la solution au comportement étrange après la réouverture de l'application depuis l'arrière-plan. Dans mon application, l'ouverture à partir de l'arrière-plan superposait mon écran d'accueil (contrôleur de vue initial) en tant que style de présentation de carte, puis toutes les séquences à partir de ce moment-là effectuaient un fondu enchaîné au lieu d'utiliser mon style de séquence défini. Tout se passe bien si je ferme l'application (en appuyant deux fois sur le bouton d'accueil et en faisant glisser le curseur vers le haut, puis en la rouvrant), mais tout lancement supplémentaire entraîne ce comportement étrange. Merci encore !

122voto

Il y a de multiples façons de faire cela, et je pense que chacune d'entre elles pourrait convenir à un projet mais pas à un autre, alors j'ai pensé les garder ici, peut-être que quelqu'un d'autre tombera sur un cas différent.

1- Annulation présente

Si vous avez un BaseViewController vous pouvez remplacer le present(_ viewControllerToPresent: animated flag: completion:) méthode.

class BaseViewController: UIViewController {

  // ....

  override func present(_ viewControllerToPresent: UIViewController,
                        animated flag: Bool,
                        completion: (() -> Void)? = nil) {
    viewControllerToPresent.modalPresentationStyle = .fullScreen
    super.present(viewControllerToPresent, animated: flag, completion: completion)
  }

  // ....
}

En utilisant cette méthode, vous n'avez pas besoin d'effectuer de changement sur aucun des éléments suivants present car nous venons d'annuler l'appel present méthode.

2- Une extension :

extension UIViewController {
  func presentInFullScreen(_ viewController: UIViewController,
                           animated: Bool,
                           completion: (() -> Void)? = nil) {
    viewController.modalPresentationStyle = .fullScreen
    present(viewController, animated: animated, completion: completion)
  }
}

Utilisation :

presentInFullScreen(viewController, animated: true)

3- Pour un UIViewController

let viewController = UIViewController()
viewController.modalPresentationStyle = .fullScreen
present(viewController, animated: true, completion: nil)

4- Du Storyboard

Sélectionnez un enchaînement et réglez la présentation sur FullScreen .
enter image description here

5- Swizzling

extension UIViewController {

  static func swizzlePresent() {

    let orginalSelector = #selector(present(_: animated: completion:))
    let swizzledSelector = #selector(swizzledPresent)

    guard let orginalMethod = class_getInstanceMethod(self, orginalSelector), let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) else{return}

    let didAddMethod = class_addMethod(self,
                                       orginalSelector,
                                       method_getImplementation(swizzledMethod),
                                       method_getTypeEncoding(swizzledMethod))

    if didAddMethod {
      class_replaceMethod(self,
                          swizzledSelector,
                          method_getImplementation(orginalMethod),
                          method_getTypeEncoding(orginalMethod))
    } else {
      method_exchangeImplementations(orginalMethod, swizzledMethod)
    }

  }

  @objc
  private func swizzledPresent(_ viewControllerToPresent: UIViewController,
                               animated flag: Bool,
                               completion: (() -> Void)? = nil) {
    if #available(iOS 13.0, *) {
      if viewControllerToPresent.modalPresentationStyle == .automatic {
        viewControllerToPresent.modalPresentationStyle = .fullScreen
      }
    }
    swizzledPresent(viewControllerToPresent, animated: flag, completion: completion)
   }
}

Utilisation :
Dans votre AppDelegate à l'intérieur de application(_ application: didFinishLaunchingWithOptions) ajouter cette ligne :

UIViewController.swizzlePresent()

En utilisant cette méthode, vous n'avez pas besoin de modifier les appels actuels, car nous remplaçons l'implémentation de la méthode actuelle en cours d'exécution.
Si vous voulez savoir ce qu'est le swizzling, vous pouvez consulter ce lien : https://nshipster.com/swift-objc-runtime/

48voto

kuzdu Points 2293

Un conseil : si vous appelez present à un ViewController qui est intégré dans un NavigationController vous devez définir le NavigationController à .fullScreen et non le VC.

Vous pouvez le faire comme @davidbates ou le faire de manière programmatique (comme @pascalbros).

Il en va de même pour le UITabViewController

Un exemple de scénario pour NavigationController :

enter image description here

    //BaseNavigationController: UINavigationController {}
    let baseNavigationController = storyboard!.instantiateViewController(withIdentifier: "BaseNavigationController")
    var navigationController = UINavigationController(rootViewController: baseNavigationController)
    navigationController.modalPresentationStyle = .fullScreen
    navigationController.topViewController as? LoginViewController
    self.present(navigationViewController, animated: true, completion: nil)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X