IOS 13 Beta 1では、モーダルビューコントローラーの新しい動作が表示されます。現在、デフォルトでは全画面表示ではなく、下にスライドしようとすると、アプリはView Controllerを自動的に閉じます。
この動作を防ぎ、古いフルスクリーンモーダルvcに戻すにはどうすればよいですか?
ありがとう
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)
それを行うには複数の方法があり、それぞれが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
呼び出しを変更する必要はありません。
_extension UIViewController {
func presentInFullScreen(_ viewController: UIViewController,
animated: Bool,
completion: (() -> Void)? = nil) {
viewController.modalPresentationStyle = .fullScreen
present(viewController, animated: animated, completion: completion)
}
}
_
使用法:
_presentInFullScreen(viewController, animated: true)
_
_let viewController = UIViewController()
viewController.modalPresentationStyle = .fullScreen
present(viewController, animated: true, completion: nil)
_
セグエを選択し、プレゼンテーションをFullScreen
に設定します。
_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/
Objective-Cユーザーの場合
このコードを使用してください
[vc setModalPresentationStyle: UIModalPresentationFullScreen];
または、iOS 13.0で特定の機能を追加したい場合は、
if (@available(iOS 13.0, *)) {
[vc setModalPresentationStyle: UIModalPresentationFullScreen];
} else {
// Fallback on earlier versions
}
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
}
一発ギャグ:
modalPresentationStyle
はnavigationController提示中で設定する必要があります。
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で設定する必要があります。
ヒント:ViewController
内に埋め込まれているNavigationController
にpresentを呼び出す場合、VCではなくNavigationController
を.fullScreen
に設定する必要があります。
@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)
これがObjective-Cのソリューションです
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ViewController *vc = [storyBoard instantiateViewControllerWithIdentifier:@"ViewController"];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:vc animated:YES completion:nil];
カテゴリを使用した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
他のすべての答えは十分ですが、私たちのような大規模なプロジェクトで、コードとストーリーボードの両方でナビゲーションが行われている場合、それは非常に困難な作業です。
ストーリーボードを積極的に使用している人向け。これは私のアドバイスです:正規表現を使用してください。
次の形式は、全画面ページには適していません。
<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"/>
最初は、modalPresentationStyleのデフォルト値はfullscreen
ですが、iOS 13ではUIModalPresentationStyle.automatic
。
フルスクリーンのView Controllerを作成する場合は、modalPresentationStyle
をfullScreen
に変更する必要があります。
詳細についてはUIModalPresentationStyle
Appleドキュメント を参照し、どこでどのモダリティを使用すべきか Appleヒューマンインターフェイスガイドライン を参照してください。
let Obj = MtViewController()
Obj.modalPresentationStyle = .overFullScreen
self.present(Obj, animated: true, completion: nil)
//スワイプを無効にして無効にする場合は、行を追加します
Obj.isModalInPresentation = true
Apple Document で詳細を確認してください。
これは簡単に行えます。ストーリーボードをソースコードとして開き、kind="presentation"
、kind = presentationのすべてのseagueタグに追加の属性modalPresentationStyle="fullScreen"
UIViewControllerのカテゴリを作成します(たとえば、UIViewController + PresentationStyle)。次のコードを追加します。
-(UIModalPresentationStyle)modalPresentationStyle{
return UIModalPresentationStyleFullScreen;
}
これは私のために働いた:
yourViewController.modalPresentationStyle = UIModalPresentationStyle.fullScreen
ビデオが全画面表示されなくなったため、この問題が発生しました。この行を追加して、1日を節約しました:-)
videoController.modalPresentationStyle = UIModalPresentationFullScreen;
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
を使用できます。
提示する前にmodalPresentationStyleを変更する
vc.modalPresentationStyle = UIModalPresentationFullScreen;
別のアプローチは、アプリに独自のベース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でテスト済み
それが役に立てば幸い
UINavigationControllerを使用していて、ViewControllerをルートView Controllerとして埋め込む場合、同じ問題が発生します。次のコードを使用して克服します。
let vc = UIViewController()
let navController = UINavigationController(rootViewController: vc)
navController.modalPresentationStyle = .fullScreen
私のために働いた最も簡単な解決策。
viewController.modalPresentationStyle = .fullScreen