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 

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 

@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添加:

UIUserInterfaceStyle
Light

或者

//强制关闭暗黑模式
#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
    if(@available(iOS 13.0,*)){
        self.window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
    }
#endif

单个界面不遵循暗黑模式

在iOS13,为UIViewController和UIView扩展了一个新的API

@property(nonatomic) UIUserInterfaceStyle overrideUserInterfaceStyle;

将 overrideUserInterfaceStyle 设置为对应的模式,则强制限制该元素与其子元素以设置的模式进行展示,不跟随系统模式改变进行改变
设置 ViewController 的该属性, 将会影响视图控制器的视图和子视图控制器采用该样式
设置 View 的该属性, 将会影响视图及其所有子视图采用该样式
设置 Window 的该属性, 将会影响窗口中的所有内容都采用样式,包括根视图控制器和在该窗口中显示内容的所有演示控制器(UIPresentationController)

开启暗黑模式

+ (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
}

模拟器调试
运行项目
点击Xcode底部调试栏中Environment Overrides
开启Interface Style,就可以切换了。

三、废弃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 进行审批。

你可能感兴趣的:(iOS13 适配)