web-dev-qa-db-ja.com

iOS 13フルスクリーンでのモーダルの提示

IOS 13 Beta 1では、モーダルビューコントローラーの新しい動作が表示されます。現在、デフォルトでは全画面表示ではなく、下にスライドしようとすると、アプリはView Controllerを自動的に閉じます。

この動作を防ぎ、古いフルスクリーンモーダルvcに戻すにはどうすればよいですか?

modal behaviour

ありがとう

389
pascalbros

IOS 13では、WWDC 2019の Platforms State of the Union で述べられているように、Appleは新しいデフォルトのカードプレゼンテーションを導入しました。フルスクリーンを強制するには、明示的に指定するには:

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

誰かに役立つ情報を追加します。ストーリーボードセグエがある場合、古いスタイルに戻るには、kindプロパティをに設定する必要がありますModallyPresentationプロパティをFull Screen

enter image description here

159
Alessandro

起動画面の直後の初期ビューでこの問題が発生しました。セグエやロジックが定義されていなかったので、ここに示すように、プレゼンテーションを自動からフルスクリーンに切り替えることで私を修正しました。

fix_storyboard_presentation_default_behavior

83
davidbates

それを行うには複数の方法があり、それぞれが1つのプロジェクトに適合しても別のプロジェクトには適合しないと思うので、私はそれらをここに保持し、他の誰かが別のケースに出くわすかもしれないと思った。

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- 1つの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/

76

Objective-Cユーザーの場合

このコードを使用してください

 [vc setModalPresentationStyle: UIModalPresentationFullScreen];

または、iOS 13.0で特定の機能を追加したい場合は、

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

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

どこかで

たとえば、AppDelegateで

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {

    UIViewController.preventPageSheetPresentation
    // ...
    return true
}
31
Maxime Ashurov

一発ギャグ:

modalPresentationStylenavigationController提示中で設定する必要があります。


overCurrentContextおよびnavigationControllerを含むiOSバージョン13以下のiOSバージョン

テスト済みコード

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

modalPresentationStylenavigationControllerで設定する必要があります。

27
Pratik Sodha

ヒント:ViewController内に埋め込まれているNavigationControllerにpresentを呼び出す場合、VCではなくNavigationController.fullScreenに設定する必要があります。

@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)
23
kuzdu

私は両方を行う必要がありました:

  1. プレゼンテーションスタイルをフルスクリーンに設定する

    Full screen

  2. トップバーを半透明ナビゲーションバーとして設定

Top bar

12
vedrano

これがObjective-Cのソリューションです

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

vc.modalPresentationStyle = UIModalPresentationFullScreen;

[self presentViewController:vc animated:YES completion:nil];
11
Prashanth Thota

ナビゲーションコントローラーが埋め込まれた画面を備えたUITabControllerがある場合は、下の写真に示すように、UITabControllerPresentationをFullScreenに設定する必要があります。

enter image description here

11
Di Nerd

これは、単一行をコーディングせずに簡単なソリューションです。

  • ストーリーボードでView Controllerを選択します
  • 属性インスペクターを選択
  • 下の画像のように、プレゼンテーション「自動」を「フルスクリーン」に設定します

この変更により、iPadアプリの動作が期待どおりになります。そうしないと、新しい画面が画面の中央にポップアップとして表示されます。

enter image description here

11
Mahesh Cheliya

カテゴリを使用した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

他のすべての答えは十分ですが、私たちのような大規模なプロジェクトで、コードとストーリーボードの両方でナビゲーションが行われている場合、それは非常に困難な作業です。

enter image description here

ストーリーボードを積極的に使用している人向け。これは私のアドバイスです:正規表現を使用してください。

次の形式は、全画面ページには適していません。

<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"/>
7
Bangonkali

最初は、modalPresentationStyleのデフォルト値はfullscreenですが、iOS 13ではUIModalPresentationStyle.automatic

フルスクリーンのView Controllerを作成する場合は、modalPresentationStylefullScreenに変更する必要があります。

詳細についてはUIModalPresentationStyleAppleドキュメント を参照し、どこでどのモダリティを使用すべきか Appleヒューマンインターフェイスガイドライン を参照してください。

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

//スワイプを無効にして無効にする場合は、行を追加します

Obj.isModalInPresentation = true

Apple Document で詳細を確認してください。

2
Mohit Tomar

これは簡単に行えます。ストーリーボードをソースコードとして開き、kind="presentation"、kind = presentationのすべてのseagueタグに追加の属性modalPresentationStyle="fullScreen"

2
amar

UIViewControllerのカテゴリを作成します(たとえば、UIViewController + PresentationStyle)。次のコードを追加します。

 -(UIModalPresentationStyle)modalPresentationStyle{
     return UIModalPresentationStyleFullScreen;
}
1
Govind

これは私のために働いた:

yourViewController.modalPresentationStyle = UIModalPresentationStyle.fullScreen

1
Dian

ビデオが全画面表示されなくなったため、この問題が発生しました。この行を追加して、1日を節約しました:-)

videoController.modalPresentationStyle = UIModalPresentationFullScreen;
0
user1737746
class MyViewController: UIViewController {

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

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

すべてのView Controllerに対してself.modalPresentationStyle = .fullScreenを呼び出すのではなく、UIViewControllerをサブクラス化し、すべての場所でMyViewControllerを使用できます。

0
Peter Tao

提示する前にmodalPresentationStyleを変更する

vc.modalPresentationStyle = UIModalPresentationFullScreen;

0
MAMN84

別のアプローチは、アプリに独自のベース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
    }
}

[〜#〜] note [〜#〜]:View Controllerが実際にモーダルで表示されるNavigation Controllerに含まれている場合、Navigation Controllerは同じ方法で問題にアプローチする必要があります(つまり、カスタムNavigation Controllerコンポーネントを同じ方法でカスタマイズする

iOS 13.1およびiOS 12.4のXcode 11.1でテスト済み

それが役に立てば幸い

0
Luca Iaco

UINavigationControllerを使用していて、ViewControllerをルートView Controllerとして埋め込む場合、同じ問題が発生します。次のコードを使用して克服します。

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

私のために働いた最も簡単な解決策。

viewController.modalPresentationStyle = .fullScreen
0
Fahad Azeem