iOS 13,使用 presentViewController 方式打开视图,会跟导航栏有部分视觉差,如下图
原因:苹果将 UIViewController
的 modalPresentationStyle
属性的默认值改成了新加的一个枚举值 UIModalPresentationAutomatic
,对于多数UIViewController
,此值会映射成 UIModalPresentationPageSheet
解决办法: 可以在vcpresent
之前设置modalPresentationStyle
为 UIModalPresentationStyle.fullScreen
另外,present
的vc用户下拉可以dissmiss
控制器,如果不想要这效果,可以这样设置vc.isModalInPresentation = true
注意:原来以UIModalPresentation.fullScreen
样式弹出页面,那么这个页面弹出 ViewController
会依次调viewWillDisappear
和 viewDidDisappear
。然后在这个页面被 dismiss
的时候,将他弹出的那个 ViewController
的 viewWillAppear
和 viewDidAppear
会被依次调用。然而使用默认的视差效果弹出页面,将他弹出的那个 ViewController
并不会调用这些方法,原先写在这四个函数中的代码以后都有可能会存在问题
改进:如果设置每个跳转都设置UIModalPresentation.fullScreen
对代码的侵入性太强,这个时候可以使用方法交换来对进行扩展,具体代码如下:
swift
import Foundation
import UIKit
/**众所周知方法交换一般都在单例中进行,但是 OC中用来保证代码块只执行一次的dispatch_once在swfit中已经被废弃了,取而代之的是使用static let,let本身就带有线程安全性质的.
+load(): app启动的时候会加载所有的类,此时就会调用每个类的load方法.
+initialize(): 第一次初始化这个类的时候会被调用.
然而在目前的swift版本中这两个方法都不可用了,那现在我们要在这个阶段搞事情该怎么做? 例如method swizzling.
JORDAN SMITH大神给出了一种很巧解决方案.UIApplication有一个next属性,它会在applicationDidFinishLaunching之前被调用,这个时候通过runtime获取到所有类的列表,然后向所有遵循SelfAware协议的类发送消息.
*/
extension UIApplication {
private static let runOnce: Void = {
NothingToSeeHere.harmlessFunction()
}()
override open var next: UIResponder? {
// Called before applicationDidFinishLaunching
UIApplication.runOnce
return super.next
}
}
class NothingToSeeHere {
static func harmlessFunction() {
let typeCount = Int(objc_getClassList(nil, 0))
let types = UnsafeMutablePointer<AnyClass>.allocate(capacity: typeCount)
let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(types)
objc_getClassList(autoreleasingTypes, Int32(typeCount))
for index in 0 ..< typeCount {
(types[index] as? SelfAware.Type)?.awake()
}
types.deallocate()
}
}
protocol SelfAware:class {
static func awake()
static func swizzlingForClass(_ forClass:AnyClass,originalSelector:Selector,swizzledSelector:Selector)
}
extension SelfAware{
static func swizzlingForClass(_ forClass:AnyClass,originalSelector:Selector,swizzledSelector:Selector){
let originalMethod = class_getInstanceMethod(forClass, originalSelector)
let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector)
guard (originalMethod != nil && swizzledMethod != nil) else {
return
}
if class_addMethod(forClass, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!)) {
class_replaceMethod(forClass, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
} else {
method_exchangeImplementations(originalMethod!, swizzledMethod!)
}
}
}
extension UIViewController:SelfAware {
static func awake() {
presentSwizzledMethod
}
private static let presentSwizzledMethod:Void = {
let originalSelector = #selector(present(_:animated:completion:))
let swizzledSelector = #selector(cl_present(_:animation:completion:))
swizzlingForClass(UIViewController.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
}()
@objc func cl_present(_ controlelr:UIViewController,animation:Bool,completion: (() -> Void)? = nil) {
print("swizzled_present")
controlelr.modalPresentationStyle = UIModalPresentationStyle.fullScreen
self.cl_present(controlelr,animation:true,completion:nil)
}
}
以上就行关于适配的方法