Представление модального в iOS 13 в полноэкранном режиме
В iOS 13 Beta 1 есть новое поведение для контроллера модального представления при представлении. Теперь это не полноэкранный режим по умолчанию, и когда я пытаюсь скользить вниз, приложение просто автоматически отключает View Controller.
Как я могу предотвратить это поведение и вернуться к старому хорошему полноэкранному модальному vc?
Спасибо
Ответы
Ответ 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 - Полный экран.
Ответ 3
У меня была эта проблема на начальном экране сразу после экрана запуска. Для меня, поскольку у меня не было определенной последовательности или логики, было переключение презентации с автоматического на полноэкранный режим, как показано здесь:
Ответ 4
Подсказка: если вы вызываете подарок на ViewController
, который встроен в NavigationController
, вы должны установить NavigationController
на .fullScreen
, а не на VC.
Вы можете сделать это как @davidbates или сделать это программно (например, @pascalbros).
Пример сценария:
//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
.
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, как показано на рисунке ниже
Ответ 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 будет работать так, как ожидалось, иначе новый экран отображается в центре экрана в виде всплывающего окна.
Ответ 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)
}
- обмен методом (я не рекомендую)