Programing

iOS 13 전체 화면에서 모달 표시

crosscheck 2020. 6. 14. 10:34
반응형

iOS 13 전체 화면에서 모달 표시


iOS 13 Beta 1에는 모달 뷰 컨트롤러가 표시 될 때 새로운 동작이 있습니다. 이제 기본적으로 전체 화면이 아니며 아래로 슬라이드하려고하면 앱이 View Controller를 자동으로 닫습니다.

이 동작을 방지하고 오래된 좋은 전체 화면 모달 vc로 돌아가려면 어떻게해야합니까?

모달 행동

감사


WWDC 2019 기간 동안 Platforms of the Union에 명시된 바와 같이 , Apple은 새로운 기본 카드 프레젠테이션을 iOS 13과 함께 발표했습니다. 전체 화면을 강제 실행하려면 다음과 같이 명시 적으로 지정해야합니다.

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

누군가에게 유용한 정보를 추가합니다. 스토리 보드 segue가있는 경우 이전 스타일로 돌아가려면 kind 속성을 Present Modally 로 설정 하고 Presentation 속성을 Full Screen 으로 설정해야합니다 .

여기에 이미지 설명을 입력하십시오


시작 화면 직후의 초기보기 에서이 문제가 발생했습니다. segue 또는 논리가 정의되지 않았기 때문에 해결 방법은 다음과 같이 프레젠테이션을 자동에서 전체 화면으로 전환하는 것이 었습니다.

fix_storyboard_presentation_default_behavior


힌트로 : ViewController안에 포함 된 에 대한 전화를 하면 VC가 아닌 NavigationController로 설정해야 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 사용자의 경우

이 코드를 사용하십시오

 [vc setModalPresentationStyle: UIModalPresentationFullScreen];

또는 iOS 13.0에서 특정 항목을 추가하려면

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

임베디드 내비게이션 컨트롤러가있는 스크린이있는 UITabController가있는 경우 아래 그림과 같이 UITabController 프리젠 테이션 을 전체 화면으로 설정해야 합니다.

여기에 이미지 설명을 입력하십시오


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

// 스 와이프하여 사용하지 않도록 설정하려면 줄을 추가하십시오.

Obj.isModalInPresentation = true

자세한 정보는 Apple 문서확인하십시오 .


여러 가지 방법이 있으며 각 프로젝트는 하나의 프로젝트에는 적합하지만 다른 프로젝트에는 적합하지 않다고 생각하므로 다른 사람이 다른 사건을 겪을 수도 있습니다.

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- 하나의 뷰 컨트롤러

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

4- 스토리 보드에서

세 구아를 선택하고 프레젠테이션을로 설정하십시오 FullScreen.
여기에 이미지 설명을 입력하십시오

5- 스위 즐링

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/


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

어딘가에


위의 답변과 제안은 옳으며 아래는 다른 버전이며 프로그래밍 방식으로 효율적으로 사용하는 방법입니다.

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

Objective-C에서 내가 찾은 두 가지 방법.

두 열거 형 modalPresentationStyles가 모두 0보다 작은 것을 알았습니다.

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];
}
  • 분석법 교환 (권장하지 않음)

참고 URL : https://stackoverflow.com/questions/56435510/presenting-modal-in-ios-13-fullscreen

반응형