全屏显示iOS 13中的模态

时间:2019-06-03 23:01:50

标签: ios viewcontroller modalviewcontroller ios13

在iOS 13 Beta 1中,出现模态视图控制器时有新行为。 现在默认情况下它不是全屏显示,当我尝试向下滑动时,该应用程序会自动关闭View Controller。

如何防止这种情况并回到旧的全屏模态vc?

modal behaviour

谢谢

33 个答案:

答案 0 :(得分:75)

启动屏幕后,我在初始视图上就遇到了这个问题。因为没有定义顺序或逻辑,所以对我的解决方法是将演示文稿从自动切换到全屏,如下所示:

fix_storyboard_presentation_default_behavior

答案 1 :(得分:65)

有多种方法可以做到这一点,我认为每个项目都可以适合一个项目,但不适合另一个项目,所以我想我将它们保留在这里,也许其他人会遇到不同的情况。

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-晕眩

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)
   }
}

用法:
AppDelegate内的application(_ application: didFinishLaunchingWithOptions)中,添加以下行:

UIViewController.swizzlePresent()

使用这种方式,您无需在任何当前调用上进行任何更改,因为我们正在替换运行时中的当前方法实现。
如果您想知道什么在泛滥,可以查看以下链接: https://nshipster.com/swift-objc-runtime/

答案 2 :(得分:30)

对于Objective-C用户

只需使用此代码

 [vc setModalPresentationStyle: UIModalPresentationFullScreen];

或者如果您想在iOS 13.0中添加它,请使用

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

答案 3 :(得分:22)

作为提示:如果调用存在于createdAt中的ViewController,则必须将NavigationController设置为NavigationController,而不是VC。

您可以像@davidbates一样执行此操作,也可以以编程方式(例如@pascalbros)来执行此操作。

示例场景:

enter image description here

.fullScreen

答案 4 :(得分:22)

最新的iOS 13和Swift 5.x

let vc = ViewController(nibName: "ViewController", bundle: nil)

vc.modalPresentationStyle = .fullScreen

self.present(vc, animated: true, completion: nil)

答案 5 :(得分:21)

如WWDC 2019期间Platforms State of the Union所述,使用iOS 13,Apple引入了新的默认卡演示文稿。为了强制全屏,您必须使用以下命令明确指定它:

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

答案 6 :(得分:21)

我在iOS 13上使用了swizzling

.date-time { display: none; }

@media screen and (min-width: 300px) {
 .size-s .date-time { display: inline-block; }
}

@media screen and (min-width: 576px) {
 .size-m .date-time { display: inline-block; }
}

@media screen and (min-width: 800px) {
 .size-l .date-time { display: inline-block; }
}

然后放这个

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)
    }
}

某处

例如在AppDelegate中

UIViewController.preventPageSheetPresentation

答案 7 :(得分:19)

在演示前更改modalPresentationStyle

vc.modalPresentationStyle = UIModalPresentationFullScreen;

答案 8 :(得分:10)

如果您的UITabController的屏幕带有嵌入式导航控制器,则必须将UITabController 演示文稿设置为“全屏”,如下图所示

enter image description here

答案 9 :(得分:9)

这是一个简单的解决方案,无需编写一行代码。

  • 在情节提要中选择视图控制器
  • 选择属性检查器
  • 按照下图将演示文稿“自动”设置为“全屏”

此更改使iPad应用程序具有预期的行为,否则新屏幕将在弹出窗口的中央显示。

enter image description here

答案 10 :(得分:9)

快速解决方案。上面已经有非常好的答案。我还添加了我的快速2点输入,该输入显示在屏幕截图中。

  1. 如果您不使用Navigation Controller,则从Right Menu Inspector将Presentation设置为Full Screen

  2. 如果您使用的是Navigation Controller,则默认情况下它将以全屏显示,您无需执行任何操作。

enter image description here

答案 11 :(得分:7)

这是Objective-C的解决方案

UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ViewController *vc = [storyBoard instantiateViewControllerWithIdentifier:@"ViewController"];

vc.modalPresentationStyle = UIModalPresentationFullScreen;

[self presentViewController:vc animated:YES completion:nil];

答案 12 :(得分:6)

所有其他答案都足够了,但是对于像我们这样的大型项目来说,在代码和情节提要中都进行导航时,这是一项艰巨的任务。

enter image description here

对于那些正在积极使用Storyboard的用户。这是我的建议:使用Regex。

以下格式不适用于全屏页面:

<segue destination="Bof-iQ-svK" kind="presentation" identifier="importSystem" modalPresentationStyle="fullScreen" id="bfy-FP-mlc"/>

以下格式适合全屏页面:

<segue destination="7DQ-Kj-yFD" kind="presentation" identifier="defaultLandingToSystemInfo" modalPresentationStyle="fullScreen" id="Mjn-t2-yxe"/>

以下与VS CODE兼容的正则表达式会将所有旧样式页面转换为新样式页面。如果您使用其他正则表达式引擎/文本编辑器,则可能需要转义特殊字符。

搜索正则表达式

<segue destination="(.*)"\s* kind="show" identifier="(.*)" id="(.*)"/>

替换正则表达式

<segue destination="$1" kind="presentation" identifier="$2" modalPresentationStyle="fullScreen" id="$3"/>

答案 13 :(得分:6)

我需要同时做这两项:

  1. 将演示文稿样式设置为“全屏”

    Full screen

  2. 将顶部栏设置为半透明导航栏

Top bar

答案 14 :(得分:6)

这对我有用

`让vc = self.storyboard?.instantiateViewController(withIdentifier:“ cameraview1”)为! CameraViewController

    vc.modalPresentationStyle = .fullScreen
    
self.present(vc, animated: true, completion: nil)`

答案 15 :(得分:5)

  

iOS 13及更低版本的iOS版全屏,带有overCurrentContext和   navigationController

测试代码

let controller = UIViewController()
let navigationController = UINavigationController(rootViewController: controller)
navigationController.modalPresentationStyle = .overCurrentContext
self.navigationController?.present(navigationController, animated: true, completion: nil)

modalPresentationStyle 需要在 navigationController 上进行设置。

答案 16 :(得分:4)

我添加了可能对某人有用的信息。如果您有任何情节提要,请回到旧样式,需要将种类属性设置为模态呈现演示文稿属性进入全屏

enter image description here

答案 17 :(得分:3)

最初,modalPresentationStyle的默认值为/** * @group table */ public function testVisit() { $this->browse(function (Browser $browser) { $user = factory(User::class)->create(['user_type' => 'admin']); $browser->maximize(); $browser->loginAs(factory(User::class)->create(['user_type' => 'admin'])); $browser->visit('/admin/logs'); $browser->assertTitle('talbase - User Activity'); $browser->assertSee('User Activity'); $browser->waitFor('table'); $browser->assertVisible('#user_log_list'); $browser->whenAvailable('table#user_log_list', function($table) use ($user) { $table->pause(2000); $table->assertSee($user->first_name); }); $browser->pause(5000); $browser->logout(); }); } ,但在 iOS 13 中,其默认值为fullscreen

如果要制作全屏视图控制器,则必须将UIModalPresentationStyle.automatic更改为modalPresentationStyle

有关更多详细信息,请参见fullScreen apple documentation,有关在何处应使用哪种模式的信息,请参见apple human interface guidelines

答案 18 :(得分:3)

我通过使用swizzling(Swift 4.2)方法实现了此目标:

要创建如下的UIViewController扩展

extension UIViewController {

    @objc private func swizzled_presentstyle(_ viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?) {

        if #available(iOS 13.0, *) {
            if viewControllerToPresent.modalPresentationStyle == .automatic || viewControllerToPresent.modalPresentationStyle == .pageSheet {
                viewControllerToPresent.modalPresentationStyle = .fullScreen
            }
        }

        self.swizzled_presentstyle(viewControllerToPresent, animated: animated, completion: completion)
    }

     static func setPresentationStyle_fullScreen() {

        let instance: UIViewController = UIViewController()
        let aClass: AnyClass! = object_getClass(instance)

        let originalSelector = #selector(UIViewController.present(_:animated:completion:))
        let swizzledSelector = #selector(UIViewController.swizzled_presentstyle(_:animated:completion:))

        let originalMethod = class_getInstanceMethod(aClass, originalSelector)
        let swizzledMethod = class_getInstanceMethod(aClass, swizzledSelector)
        if let originalMethod = originalMethod, let swizzledMethod = swizzledMethod {
        method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }
}

以及在AppDelegate中的application:didFinishLaunchingWithOptions中:通过调用以下代码来调用混乱的代码:

UIViewController.setPresentationStyle_fullScreen()

答案 19 :(得分:2)

这是我在ObjectiveC中使用类别的修复版本。使用这种方法,您将拥有默认的UIModalPresentationStyleFullScreen行为,直到明确设置了另一个行为为止。

#import "UIViewController+Presentation.h"
#import "objc/runtime.h"

@implementation UIViewController (Presentation)

- (void)setModalPresentationStyle:(UIModalPresentationStyle)modalPresentationStyle {
    [self setPrivateModalPresentationStyle:modalPresentationStyle];
}

-(UIModalPresentationStyle)modalPresentationStyle {
    UIModalPresentationStyle style = [self privateModalPresentationStyle];
    if (style == NSNotFound) {
        return UIModalPresentationFullScreen;
    }
    return style;
}

- (void)setPrivateModalPresentationStyle:(UIModalPresentationStyle)modalPresentationStyle {
    NSNumber *styleNumber = [NSNumber numberWithInteger:modalPresentationStyle];
     objc_setAssociatedObject(self, @selector(privateModalPresentationStyle), styleNumber, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (UIModalPresentationStyle)privateModalPresentationStyle {
    NSNumber *styleNumber = objc_getAssociatedObject(self, @selector(privateModalPresentationStyle));
    if (styleNumber == nil) {
        return NSNotFound;
    }
    return styleNumber.integerValue;
}

@end

答案 20 :(得分:2)

navigationController.modalPresentationStyle 设置为 .fullScreen 在这里已经重复了一千多次,但让我向您展示另一个阻止 UIViewController / UINavigationController 没有显示在fullscreen 即使所有属性都设置正确。

就我而言,罪魁祸首隐藏在这一行中

navigationController?.presentationController?.delegate = self

显然设置 UIAdaptivePresentationControllerDelegate 会将样式更改为 pageSheet

答案 21 :(得分:2)

您可以轻松地这样做 打开情节提要作为源代码并搜索kind="presentation",在所有带有kind = present的seague标签中添加一个额外的属性modalPresentationStyle="fullScreen"

答案 22 :(得分:2)

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

//如果要禁用滑动以关闭它,请添加行

Obj.isModalInPresentation = true

检查Apple Document以获得更多信息。

答案 23 :(得分:1)

为UIViewController创建类别(例如,UIViewController + PresentationStyle)。向其中添加以下代码。

 -(UIModalPresentationStyle)modalPresentationStyle{
     return UIModalPresentationStyleFullScreen;
}

答案 24 :(得分:1)

这对我有用:

yourViewController.modalPresentationStyle = UIModalPresentationStyle.fullScreen

答案 25 :(得分:0)

class MyViewController: UIViewController {

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

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

您可以继承UIViewController的子类,而不必在每个视图控制器上调用self.modalPresentationStyle = .fullScreen

答案 26 :(得分:0)

如果您正在使用UINavigationController并将ViewController嵌入为根视图控制器,那么您也会遇到同样的问题。使用以下代码来克服。

 this.questions
        .pipe(
          map(results => {
            return results.sort((a, b) => {
              let res = compareString(a[column].replace(/<.*?>/g, ''), 
b[column].replace(/<.*?>/g, ''));
              debugger;
              return direction === 'asc' ? res : -res;
            })
          })
        ).subscribe();


export const compareString = ( a, b ) => {
if ( a < b ){
    return -1;
  }
  if ( a > b ){
    return 1;
  }
  return 0;
}

答案 27 :(得分:0)

最适合我的解决方案。

viewController.modalPresentationStyle = .fullScreen

答案 28 :(得分:0)

我遇到了视频无法再全屏显示的问题。添加了这一行,从而节省了一天:-)

videoController.modalPresentationStyle = UIModalPresentationFullScreen;

答案 29 :(得分:0)

另一种方法是在您的应用程序中拥有您自己的基本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
    }
}

注意:如果视图控制器包含在以模态形式实际显示的导航控制器中,则导航控制器应以相同的方式解决该问题(即,自定义自定义的导航控制器组件以同样的方式

在iOS 13.1和iOS 12.4的Xcode 11.1上测试

希望有帮助

答案 30 :(得分:-1)

由于无法解决问题,我不得不将某些导航控制器切换回全屏模式。

如果我有两个设置为自动,一个被称为另一个,则第二个控制器在屏幕边缘出现,并带有右键。

第一个控制器显示如下:

enter image description here

如果我随后用NavigationController搜寻到另一个ViewController,则看起来像这样:

enter image description here

为什么在第二个ViewController中,右键单击边缘而不是边缘?还要注意减小的高度。

如果我将第一个导航控制器更改为全屏,则第二个导航控制器将正确显示。

答案 31 :(得分:-1)

上面的答案和建议是正确的,下面是另一个版本,并且是通过编程有效使用的方式。

#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)

OR

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

答案 32 :(得分:-1)

在Objective-C中,我找到了两种方法。

我注意到两个枚举modalPresentationStyles都小于零

  

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 (viewControllerToPresent.modalPresentationStyle < 0){
        viewControllerToPresent.modalPresentationStyle = UIModalPresentationFullScreen;
    }
    [super presentViewController:viewControllerToPresent animated:flag completion:completion];
}
  • 方法交换