问题描述
[Q& A] 是否可以在iOS 13上全局更改UIViewController.modalPresentationStyle
值,使其表现得像在iOS 12(或更早版本)上一样?
[Q&A] Is it possible to change UIViewController.modalPresentationStyle
value globally on iOS 13 so it behaves like it used to on iOS 12 (or earlier)?
为什么?
在iOS 13 SDK中,UIViewController.modalPresentationStyle
属性的默认值已从UIModalPresentationFullScreen
更改为UIModalPresentationAutomatic
,据我所知,在iOS设备或至少在iPhone上已解析为UIModalPresentationPageSheet
.
In iOS 13 SDK the default value of UIViewController.modalPresentationStyle
property has been changed from UIModalPresentationFullScreen
to UIModalPresentationAutomatic
which is, as far as I know, resolved to UIModalPresentationPageSheet
on iOS devices or at least on iPhones.
由于我已经工作了几年的项目变得非常庞大,所以在很多地方都提供了视图控制器.新的演示样式并不总是与我们的应用程序设计匹配,有时会导致UI崩溃.这就是为什么我们决定将UIViewController.modalPresentationStyle
改回UIModalPresentationFullScreen
,因为它是iOS13 SDK之前的版本.
Since the project I've been working for several years has become quite big, there are tens of places where a view controller is presented. The new presentation style doesn't always match our app designs and sometimes it causes the UI to fall apart. Which is why, we deciced to change UIViewController.modalPresentationStyle
back to UIModalPresentationFullScreen
as it was is pre-iOS13 SDK's versions.
但是在每个出现控制器的地方,在调用presentViewController:animated:completion:
之前添加viewController.modalPresentationStyle = UIModalPresentationFullScreen
似乎是过大的选择.而且,那时我们还有更严重的事情要处理,这就是为什么暂时或至少在我们更新设计并解决所有UI问题之前,我们决定采用方法混淆方法的原因.
But adding viewController.modalPresentationStyle = UIModalPresentationFullScreen
before calling presentViewController:animated:completion:
in every single place where a controller is presented seemed like an overkill. Moreover, we had more serious matters to deal with at that time, which is why, for the time being or at least until we update our designs and fix all the UI issues, we decided to go with method swizzling approach.
答案中提供了可行的解决方案,但是希望您能收到任何反馈,告诉我这种方法可能带来的负面影响或后果.
推荐答案
以下是我们通过使用swizzling方法实现的方法:
Objective-C
UIViewController + iOS13Fixes.h
UIViewController+iOS13Fixes.h
#import <Foundation/Foundation.h>
@interface UIViewController (iOS13Fixes)
@end
UIViewController + iOS13Fixes.m
UIViewController+ iOS13Fixes.m
#import <objc/runtime.h>
@implementation UIViewController (iOS13Fixes)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(presentViewController:animated:completion:);
SEL swizzledSelector = @selector(swizzled_presentViewController:animated:completion:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL methodExists = !class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (methodExists) {
method_exchangeImplementations(originalMethod, swizzledMethod);
} else {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
});
}
- (void)swizzled_presentViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated completion:(void (^)())completion {
if (@available(iOS 13.0, *)) {
if (viewController.modalPresentationStyle == UIModalPresentationAutomatic || viewController.modalPresentationStyle == UIModalPresentationPageSheet) {
viewController.modalPresentationStyle = UIModalPresentationFullScreen;
}
}
[self swizzled_presentViewController:viewController animated:animated completion:completion];
}
@end
快速
UIViewController + iOS13Fixes.swift
UIViewController+iOS13Fixes.swift
import UIKit
@objc public extension UIViewController {
private func swizzled_present(_ viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?) {
if #available(iOS 13.0, *) {
if viewControllerToPresent.modalPresentationStyle == .automatic || viewControllerToPresent.modalPresentationStyle == .pageSheet {
viewControllerToPresent.modalPresentationStyle = .fullScreen
}
}
self.swizzled_present(viewControllerToPresent, animated: animated, completion: completion)
}
@nonobjc private static let _swizzlePresentationStyle: Void = {
let instance: UIViewController = UIViewController()
let aClass: AnyClass! = object_getClass(instance)
let originalSelector = #selector(UIViewController.present(_:animated:completion:))
let swizzledSelector = #selector(UIViewController.swizzled_present(_:animated:completion:))
let originalMethod = class_getInstanceMethod(aClass, originalSelector)
let swizzledMethod = class_getInstanceMethod(aClass, swizzledSelector)
if let originalMethod = originalMethod, let swizzledMethod = swizzledMethod {
if !class_addMethod(aClass, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) {
method_exchangeImplementations(originalMethod, swizzledMethod)
} else {
class_replaceMethod(aClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
}
}()
@objc static func swizzlePresentationStyle() {
_ = self._swizzlePresentationStyle
}
}
和AppDelegate
中的application:didFinishLaunchingWithOptions:
中,通过调用(仅用于swift版本)来调用swizzling:
and in AppDelegate
, in application:didFinishLaunchingWithOptions:
invoke the swizzling by calling (swift version only):
UIViewController.swizzlePresentationStyle()
确保只调用一次(使用dispatch_once
或类似的方法).
Make sure it's called only once (use dispatch_once
or some equivalent).
有关在此处混乱的方法的更多信息:
More on method swizzling here:
- https://nshipster.com/method-swizzling/
- https://nshipster.com/swift-objc-runtime/
- https://medium.com/rocknnull/ios或不可以-f8b0ed4a1ce6
- https://nshipster.com/method-swizzling/
- https://nshipster.com/swift-objc-runtime/
- https://medium.com/rocknnull/ios-to-swizzle-or-not-to-swizzle-f8b0ed4a1ce6
这篇关于使用方法刷新在iOS13上的所有UIViewController实例上一次更改modalPresentationStyle的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!