Представление модального в iOS 13 в полноэкранном режиме

В iOS 13 Beta 1 есть новое поведение для контроллера модального представления при представлении. Теперь это не полноэкранный режим по умолчанию, и когда я пытаюсь скользить вниз, приложение просто автоматически отключает View Controller.

Как я могу предотвратить это поведение и вернуться к старому хорошему полноэкранному модальному vc?

modal behaviour

Спасибо

Ответ 1

В iOS 13, как было указано в Платформе "Союз" во время WWDC 2019, Apple представила новую презентацию по умолчанию для карт. Чтобы включить полноэкранный режим, вы должны явно указать его с помощью:

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

Ответ 2

Я добавляю информацию, которая может быть полезна для кого-то. Если у вас есть какой-либо сценарий, чтобы вернуться к старому стилю, вам нужно установить для свойства kind значение Present Modally, а для свойства Presentation - Полный экран.

enter image description here

Ответ 3

У меня была эта проблема на начальном экране сразу после экрана запуска. Для меня, поскольку у меня не было определенной последовательности или логики, было переключение презентации с автоматического на полноэкранный режим, как показано здесь:

fix_storyboard_presentation_default_behavior

Ответ 4

Подсказка: если вы вызываете подарок на ViewController, который встроен в NavigationController, вы должны установить NavigationController на .fullScreen, а не на VC.

Вы можете сделать это как @davidbates или сделать это программно (например, @pascalbros).

Пример сценария:

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)

Ответ 5

Для пользователей Objective-C

Просто используйте этот код

 [vc setModalPresentationStyle: UIModalPresentationFullScreen];

Или, если вы хотите добавить его в iOS 13.0, используйте

 if (@available(iOS 13.0, *)) {
     [vc setModalPresentationStyle: UIModalPresentationFullScreen];
 } else {
     // Fallback on earlier versions
 }

Ответ 6

Есть несколько способов сделать это, и я думаю, что каждый из них может подходить для одного проекта, но не для другого, поэтому я подумал, что оставлю их здесь, может быть, кто-то другой перейдет к другому делу.

1- Переопределить подарок

Если у вас есть BaseViewController, вы можете переопределить метод present(_ viewControllerToPresent: animated flag: completion:).

class BaseViewController: UIViewController {

  // ....

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

  // ....
}

Используя этот способ, вам не нужно вносить никаких изменений ни в один вызов present, так как мы просто переопределили метод present.

2- Расширение:

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

Использование:

presentInFullScreen(viewController, animated: true)

3- для одного UIViewController

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

4- из раскадровки

Выберите переход и установите презентацию на FullScreen.
enter image description here

5- Swizzling

extension UIViewController {

  static func swizzlePresent() {

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

    let orginalMethod = class_getInstanceMethod(self, orginalSelector)
    let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

    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 == .pageSheet
        || viewControllerToPresent.modalPresentationStyle == .automatic {
        viewControllerToPresent.modalPresentationStyle = .fullScreen
      }
    }
    swizzledPresent(viewControllerToPresent, animated: flag, completion: completion)
   }
}

Использование:
В вашем AppDelegate внутри application(_ application: didFinishLaunchingWithOptions) добавьте эту строку:

UIViewController.swizzlePresent()

Используя этот способ, вам не нужно вносить никаких изменений в любой текущий вызов, так как мы заменяем текущую реализацию метода во время выполнения.
Если вам нужно знать, что происходит, вы можете проверить эту ссылку:https://nshipster.com/swift-objc-runtime/

Ответ 7

Если у вас есть UITabController с экранами со встроенными контроллерами навигации, вы должны установить для UITabController Presentation значение FullScreen, как показано на рисунке ниже

enter image description here

Ответ 8

Я использовал Swizzling для IOS 13

import Foundation
import UIKit

private func _swizzling(forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector) {
    if let originalMethod = class_getInstanceMethod(forClass, originalSelector),
       let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector) {
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }
}

extension UIViewController {

    static let preventPageSheetPresentation: Void = {
        if #available(iOS 13, *) {
            _swizzling(forClass: UIViewController.self,
                       originalSelector: #selector(present(_: animated: completion:)),
                       swizzledSelector: #selector(_swizzledPresent(_: animated: completion:)))
        }
    }()

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

затем поместите это

UIViewController.preventPageSheetPresentation

где-то

Ответ 9

let Obj = MtViewController()
Obj.modalPresentationStyle = .overFullScreen
self.present(Obj, animated: true, completion: nil)

//если вы хотите отключить смахивание, чтобы закрыть его, добавьте строку

Obj.isModalInPresentation = true

Проверьте Apple Document для получения дополнительной информации.

Ответ 10

альтернативный подход состоит в том, чтобы иметь свой собственный базовый компонент viewcontroller в своем приложении и просто реализовать назначенные и требуемые инициализаторы с базовой настройкой, что-то вроде следующего:

class MyBaseViewController: UIViewController {

//MARK: Initialisers

/// Alternative initializer which allows you to set the modal presentation syle
/// - Parameter modalStyle: the presentation style to be used
init(with modalStyle:UIModalPresentationStyle) {
    super.init(nibName: nil, bundle: nil)
    self.setup(modalStyle: modalStyle)
}

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    // default modal presentation style as fullscreen
    self.setup(modalStyle: .fullScreen)
}

required init?(coder: NSCoder) {
    super.init(coder: coder)
    // default modal presentation style as fullscreen
    self.setup(modalStyle: .fullScreen)
}

//MARK: Private

/// Setup the view
///
/// - Parameter modalStyle: indicates which modal presentation style to be used
/// - Parameter modalPresentation: default true, it prevent modally presented view to be dismissible with the default swipe gesture
private func setup(modalStyle:UIModalPresentationStyle, modalPresentation:Bool = true){
    if #available(iOS 13, *) {
        self.modalPresentationStyle = modalStyle
        self.isModalInPresentation = modalPresentation
    }
}

ПРИМЕЧАНИЕ: Если ваш контроллер представления содержится в контроллере навигации, который фактически представлен модально, тогда навигационный контроллер должен подходить к проблеме таким же образом (то есть настраивать свой пользовательский компонент контроллера навигации таким же образом

Протестировано на Xcode 11.1 на iOS 13.1 и iOS 12.4

Надеюсь, это поможет

Ответ 11

У меня была эта проблема с видео, не представляющим полноэкранный режим. Добавил эту строку, которая спасла день :-)

videoController.modalPresentationStyle = UIModalPresentationFullScreen;

Ответ 12

Это сработало для меня:

yourViewController.modalPresentationStyle = UIModalPresentationStyle.fullScreen

Ответ 13

Самое простое решение, которое сработало для меня.

viewController.modalPresentationStyle = .fullScreen

Ответ 14

Если вы используете UINavigationController и встраиваете ViewController в качестве корневого контроллера представления, то вы также столкнетесь с такой же проблемой. Используйте следующий код для преодоления.

let vc = UIViewController()
let navController = UINavigationController(rootViewController: vc)
navController.modalPresentationStyle = .fullScreen

Ответ 15

class MyViewController: UIViewController {

    convenience init() {
        self.init(nibName:nil, bundle:nil)
        self.modalPresentationStyle = .fullScreen
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

Вместо того, чтобы вызывать self.modalPresentationStyle = .fullScreen для каждого контроллера представления, вы можете создать подкласс UIViewController и просто использовать MyViewController везде.

Ответ 16

Вот простое решение без написания одной строки.

  • Выберите View Controller в раскадровке
  • Выберите атрибут инспектора
  • Установите презентацию "Автоматически" на "Полный экран", как показано на изображении ниже

Это изменение приводит к тому, что приложение iPad будет работать так, как ожидалось, иначе новый экран отображается в центре экрана в виде всплывающего окна.

enter image description here

Ответ 17

Приведенные выше ответы и предложения правильны, ниже приведена другая версия, и эффективный способ использования программным способом.

# 1 Создано расширение UIView

# 2 Создал метод()

//#1
extension UIViewController {

//#2
func presentLocal(_ viewControllerToPresent: UIViewController, animated flag: 
Bool, completion: (() -> Void)? = nil) {

//Reusing below 2 lines :-)
viewControllerToPresent.modalPresentationStyle = .overCurrentContext
self.present(viewControllerToPresent, animated: flag, completion: completion)

  }
}

Вызов, как показано ниже

let vc = MyViewController()
let nc = UINavigationController(rootViewController: vc)
sourceView.presentLocal(nc, animated: true, completion: nil)

ИЛИ

let vc = MyViewController()
sourceView.presentLocal(vc, animated: true, completion: nil)

Ответ 18

В Objective-C я нашел два способа.

Я заметил, что все два перечисления modalPresentationStyles меньше нуля

typedef NS_ENUM(NSInteger, UIModalPresentationStyle) {
    UIModalPresentationFullScreen = 0,
    UIModalPresentationPageSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
    UIModalPresentationFormSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
    UIModalPresentationCurrentContext API_AVAILABLE(ios(3.2)),
    UIModalPresentationCustom API_AVAILABLE(ios(7.0)),
    UIModalPresentationOverFullScreen API_AVAILABLE(ios(8.0)),
    UIModalPresentationOverCurrentContext API_AVAILABLE(ios(8.0)),
    UIModalPresentationPopover API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(tvos),
    UIModalPresentationBlurOverFullScreen API_AVAILABLE(tvos(11.0)) API_UNAVAILABLE(ios) API_UNAVAILABLE(watchos),
    UIModalPresentationNone API_AVAILABLE(ios(7.0)) = -1,
    UIModalPresentationAutomatic API_AVAILABLE(ios(13.0)) = -2,
};
  • переопределить базовый метод ViewController (я предлагаю)
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
{
    if ([self isKindOfClass:[UINavigationController class]]) {
//default is UIModalPresentationPageSheet
        viewControllerToPresent.modalPresentationStyle = UIModalPresentationFullScreen;
    }
    else if ([self isKindOfClass:[UITabBarController class]]) {
        viewControllerToPresent.modalPresentationStyle = UIModalPresentationFullScreen;
    }
    else if (viewControllerToPresent.modalPresentationStyle < 0){
        viewControllerToPresent.modalPresentationStyle = UIModalPresentationFullScreen;
    }
    [super presentViewController:viewControllerToPresent animated:flag completion:completion];
}

Swift

 override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
        if self as? UINavigationController != nil {
            //UINavigationController default is UIModalPresentationPageSheet
            viewControllerToPresent.modalPresentationStyle = .fullScreen
        }
        else if self as? UITabBarController != nil {
            viewControllerToPresent.modalPresentationStyle = .fullScreen
        }
        else if viewControllerToPresent.modalPresentationStyle.rawValue < 0 {
            viewControllerToPresent.modalPresentationStyle = .fullScreen
        }
        super.present(viewControllerToPresent, animated: flag, completion: completion)
    }
  • обмен методом (я не рекомендую)