iOS13 适配
一、模态弹窗样式适配
/*
Defines the presentation style that will be used for this view controller when it is presented modally. Set this property on the view controller to be presented, not the presenter.
If this property has been set to UIModalPresentationAutomatic, reading it will always return a concrete presentation style. By default UIViewController resolves UIModalPresentationAutomatic to UIModalPresentationPageSheet, but system-provided subclasses may resolve UIModalPresentationAutomatic to other concrete presentation styles. Participation in the resolution of UIModalPresentationAutomatic is reserved for system-provided view controllers.
Defaults to UIModalPresentationAutomatic on iOS starting in iOS 13.0, and UIModalPresentationFullScreen on previous versions. Defaults to UIModalPresentationFullScreen on all other platforms.
*/
@property(nonatomic,assign) UIModalPresentationStyle modalPresentationStyle API_AVAILABLE(ios(3.2));
添加下面等类别即可统一修改:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIViewController (MXRModalPresentationStyle)
#ifdef __IPHONE_13_0
@property (nonatomic, assign) BOOL mxr_didSetModalPresentationStyle API_AVAILABLE(ios(13.0));
#endif
@end
NS_ASSUME_NONNULL_END
#import "UIViewController+MXRModalPresentationStyle.h"
#import <objc/runtime.h>
@implementation UIViewController (MXRModalPresentationStyle)
#ifdef __IPHONE_13_0
+ (void)load {
if (@available(iOS 13.0, *)) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self mxr_swizzlingInstanceMethodWithClass:self.class
originSel:@selector(setModalPresentationStyle:)
swizzlingSel:@selector(mxr_setModalPresentationStyle:)];
[self mxr_swizzlingInstanceMethodWithClass:self.class
originSel:@selector(presentViewController:animated:completion:)
swizzlingSel:@selector(mxr_presentViewController:animated:completion:)];
});
}
}
static char MXRDidSetModalPresentationStyle;
- (void)setMxr_didSetModalPresentationStyle:(BOOL)mxr_didSetModalPresentationStyle {
objc_setAssociatedObject(self, &MXRDidSetModalPresentationStyle, @(mxr_didSetModalPresentationStyle), OBJC_ASSOCIATION_ASSIGN);
}
- (BOOL)mxr_didSetModalPresentationStyle {
id obj = objc_getAssociatedObject(self, &MXRDidSetModalPresentationStyle);
if (obj) {
return [obj boolValue];
} else {
return NO; // default value.
}
}
- (void)mxr_setModalPresentationStyle:(UIModalPresentationStyle)modalPresentationStyle {
if (@available(iOS 13.0, *)) {
self.mxr_didSetModalPresentationStyle = YES;
}
[self mxr_setModalPresentationStyle:modalPresentationStyle];
}
- (void)mxr_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
if (@available(iOS 13.0, *)) {
if (!viewControllerToPresent.mxr_didSetModalPresentationStyle &&
viewControllerToPresent.modalPresentationStyle == UIModalPresentationPageSheet) {
viewControllerToPresent.modalPresentationStyle = UIModalPresentationFullScreen;
}
}
[self mxr_presentViewController:viewControllerToPresent animated:flag completion:completion];
}
#pragma mark - Method Swizzling
+ (void)mxr_swizzlingInstanceMethodWithClass:(Class)cls originSel:(SEL)originSel swizzlingSel:(SEL)swizzlingSel {
Method originMethod = class_getInstanceMethod(cls, originSel);
Method swizzlingMethod = class_getInstanceMethod(cls, swizzlingSel);
BOOL didAddMethod = class_addMethod(cls,
originSel,
method_getImplementation(swizzlingMethod),
method_getTypeEncoding(swizzlingMethod));
if (didAddMethod) {
class_replaceMethod(cls,
swizzlingSel,
method_getImplementation(originMethod),
method_getTypeEncoding(originMethod));
} else {
method_exchangeImplementations(originMethod, swizzlingMethod);
}
}
#endif
@end
二、暗黑模式
关闭暗黑模式:
在Info.plist添加:
<key>UIUserInterfaceStyle</key>
<string>Light</string>
或者
//强制关闭暗黑模式
#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if(@available(iOS 13.0,*)){
self.window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
#endif
开启暗黑模式:
+ (void)adaptDarkMode:(UIView *)view lightColor:(UIColor *)lightColor darkColor:(UIColor *)darkColor {
#ifdef __IPHONE_13_0
if (@available(iOS 13.0, *)) {
view.backgroundColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
return darkColor;
} else {
return lightColor;
}
}];
} else {
view.backgroundColor = lightColor;
}
#endif
}
三、废弃MPMoviePlayerViewController
使用AVPlayerViewController 来替换MPMoviePlayerViewController控件
四、Sign In with Apple
Sign In with Apple will be available for beta testing this summer. It will be required as an option for users in apps that support third-party sign-in when it is commercially available later this year.
如果你的应用支持使用第三方登录,那么就必须加上苹果新推出的登录方式:Introducing Sign In with Apple。
五、私有方法 KVC 不允许使用
在 iOS 13 中不再允许使用 valueForKey、setValue:forKey: 等方法获取或设置私有属性,虽然编译可以通过,但是在运行时会直接崩溃,并提示一下崩溃信息
// 使用的私有方法
[_textField setValue:[UIColor redColor] forKeyPath:@“_placeholderLabel.textColor"];
// 崩溃提示信息
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug'
// 替换的方案
_textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"输入"attributes:@{NSForegroundColorAttributeName: [UIColor redColor]}];
六、LaunchImage 被弃用
iOS 8 之前我们是在LaunchImage 来设置启动图,但是随着苹果设备尺寸越来越多,我们需要在对应的 aseets 里面放入所有尺寸的启动图,这是非常繁琐的一个步骤。因此在 iOS 8 苹果引入了 LaunchScreen.storyboard,支持界面布局用的 AutoLayout + SizeClass ,可以很方便适配各种屏幕。
需要注意的是,苹果在 Modernizing Your UI for iOS 13 section 中提到,从2020年4月开始,所有支持 iOS 13 的 App 必须提供 LaunchScreen.storyboard,否则将无法提交到 App Store 进行审批。