转载

iOS13Xcode11趟坑(适配)

2019-10-10  本文已影响0人  ImmortalSummer

目录
.
1.presentViewController出来的控制器默认不全屏(变成卡片式了)
.
2.关于访问修改私有变量造成的闪退
.
3.如何让夜间模式(深色模式)不影响你的程序(如何关闭深色模式)
.
4.iOS 13的tabbar设置问题(tabbar的顶部横线设置失效/tabBarItem颜色失效)
.
5.Xcode11 缺失库文件导入libstdc-6.0.9
.
6.Xcode11新增SceneDelegate后如何更改window的根控制器, 并兼容iOS13以下的版本
6.1 使用SceneDelegate管理生命周期的风险: 使用UIAlertView闪退
6.2 iOS13不使用SceneDelegate

1.presentViewController出来的控制器默认不全屏(变成卡片式了)

原因:控制器的 modalPresentationStyle 属性的默认值以前是 UIModalPresentationFullScreen. iOS 13改了. 我们需要在调整前更改目标控制器的 modalPresentationStyle为UIModalPresentationFullScreen.

你也可以添加分类, 重写presentViewController方法. 以下是我的尝试, 有任何以外情况概不负责:
(分类重写原类方法, 不需要头文件引用, 即可全局起作用. 真让人不敢相信!)
分类Category重写原类方法的一些注意事项

#import <objc/runtime.h>

#import "UIViewController+PresentViewControllerOnIOS13.h"

@implementation UIViewController (PresentViewControllerOnIOS13)

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"

-(void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion{
    @try {
        
        //分类重写原类方法时, 类的方法列表, 分类的冲洗会排在前边, 原方法会排在最后. 执行时, 只有第一个会响应, 即原方法不会响应, 我们想要执行原方法, 无法使用super, 需要遍历原类的方法列表, 找到最后一个同名方法(即原方法), 然后获取方法的指针并执行
        
        viewControllerToPresent.modalPresentationStyle = UIModalPresentationFullScreen;
        
        u_int count;
        
        Method *methodsArr = class_copyMethodList([UIViewController class], &count);
        NSInteger index = 0;
        //NSLog(@"methodName begin----------------------------------------");
        for (int i = 0; i < count; i++) {
            SEL method = method_getName(methodsArr[i]);
            NSString *methodName = [NSString stringWithCString:sel_getName(method) encoding:NSUTF8StringEncoding];
            //NSLog(@"%@",methodName);
            if ([methodName isEqualToString:@"presentViewController:animated:completion:"]) {
                index = i;
                NSLog(@"methodName get ---> %d",i);
            }
        }
        //NSLog(@"methodName end----------------------------------------");
        
        SEL sel = method_getName(methodsArr[index]);
        IMP imp = method_getImplementation(methodsArr[index]);
        
        ((void (*)(id, SEL, id, BOOL, id))imp)(self, sel, viewControllerToPresent, flag, completion);
        
    } @catch (NSException *exception) {
        NSLog(@"presentViewController error %@",exception);
    }
}

#pragma clang diagnostic pop

@end

2.关于访问修改私有变量造成的闪退

//这样会闪退
//self.numTextField.placeholder = @"请输入手机号";
//[self.numTextField setValue:[UIColor getColorWithHexString:loginGray] forKeyPath:@"placeholderLabel.textColor"];
//[self.numTextField setValue:[UIFont fontWithName:@"Helvetica" size:Width414(14)] forKeyPath:@"placeholderLabel.font"];

//改成这样
self.numTextField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"请输入手机号" attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:Width414(14)],NSForegroundColorAttributeName:[UIColor getColorWithHexString:loginGray]}];

3.如何让夜间模式(深色模式)不影响你的程序(如何关闭深色模式)

全局关闭深色模式

info.plist里添加以下配置

<key>UIUserInterfaceStyle</key>
<string>Light</string>

单个控制器关闭深色模式

- (void)viewDidLoad {
    [super viewDidLoad];
    
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 13) {
        self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
    }
}

对背景色产生影响(如果不关闭深色模式)

ios13中如果你对控制器的view的backgroundColor不做设置, 背景色就会受到夜间模式的影响.
如果你不想你的app受到深色模式的影响(完全适配需要很大的工作量.), 你需要对为你的控制器的的view.backgroundColor设置为白色. 如果有tableview, 还需要吧cell的背景颜色也手动设置上. (可以设置clearColor 或者whiteColor)

对字体颜色产生影响(如果不关闭深色模式)

如果label的字体不设置颜色, 也会受到深色模式影响(夜间模式文字为白色, 背景为深色. 深色模式关闭时反之).

对tabbar的颜色(如果不关闭深色模式)

UIStatusBarStyleDefault 不再是黑色, 而是随深色模式可变(深色模式下为白色, 反之黑色)
iOS 13新增UIStatusBarStyleDarkContent 是指黑色

- (UIStatusBarStyle)preferredStatusBarStyle{
    BOOL isIOS13 = [[[UIDevice currentDevice] systemVersion] floatValue] >= 13 ? YES : NO;
    UIStatusBarStyle style = isIOS13 ? UIStatusBarStyleDarkContent : UIStatusBarStyleDefault;
    return style;
}

4.iOS 13的tabbar设置问题(tabbar的顶部横线设置失效/tabBarItem颜色失效)

问题1:
tabbar的背景色 和tabbar的顶部横线设置在iOS 13失效了.

问题2:
tabBarItem颜色失效.
隐藏tabbar以后再显示, 设置的tabBarItem颜色失效,颜色还原了(蓝色)(hidesBottomBarWhenPushed)

已知包括两种情况:
1.push控制器时, 目标控制器 vc.hidesBottomBarWhenPushed = YES ; 以隐藏底部tabbar. 返回后, 再点击其他tabbarBtn切换页面时, 点到谁谁变蓝.
2.当presentViewController模态一个控制器出来的时候, vc.modalPresentationStyle = UIModalPresentationFullScreen; 全屏模态的时候, 也相当于隐藏了tabbar, 也会出现上述现象. (但是如果不这只modalPresentationStyle属性, 即弹出页面非全屏的情况, 就不会出现tabBarItem颜色还原的问题)

解决方法:
iOS 13 新增了UITabBarAppearance对象, 用来统一管理tabbar的样式, 包括tabBarItem的颜色/tabbar的背景颜色/tabbar顶部横线的颜色 等都可以统一设置

#pragma mark - 设置tabbar的颜色样式
-(void)setTabBarColorStyle{
    
    //tabBarItem title 选中颜色
    NSMutableDictionary<NSAttributedStringKey, id> *selectedAttributes = [NSMutableDictionary dictionary];
    selectedAttributes[NSForegroundColorAttributeName] = kTabBarColor_Selected;
    
    //tabBarItem title 未选中颜色
    NSMutableDictionary<NSAttributedStringKey, id> *normalAttributes = [NSMutableDictionary dictionary];
    normalAttributes[NSForegroundColorAttributeName] = kTabBarColor_Normal;
    
    //tabbar 背景颜色
    UIColor *bgColor = RGBCOLOR(255, 255, 255);
    UIImage *bgImage = [self createImageForColor:bgColor withImageSize:CGSizeMake(kScreenShortSide, kTabBarHeight)];
    
    //tabbar上边的一条灰线
    UIColor *shadowImageColor = RGBCOLOR(250, 250, 250);
    UIImage *shadowImage = [self createImageForColor:shadowImageColor withImageSize:CGSizeMake(kScreenShortSide, 1)];
    
    if (IOS13) {
        UITabBarAppearance *tabBarAppearance = [[UITabBarAppearance alloc] init];
        //设置 tabBarItem title 颜色
        tabBarAppearance.stackedLayoutAppearance.selected.titleTextAttributes = selectedAttributes.copy;
        tabBarAppearance.stackedLayoutAppearance.normal.titleTextAttributes = normalAttributes.copy;
        //设置 tabbar背景色
        tabBarAppearance.backgroundImage = bgImage;
        //设置 tabbar上边的一条灰线
        tabBarAppearance.shadowColor = shadowImageColor;
        self.tabBar.standardAppearance = tabBarAppearance;
    }
    else{
        //设置 tabBarItem title 颜色
        for (UIViewController *vc in self.viewControllers) {
            [vc.tabBarItem setTitleTextAttributes:normalAttributes.copy forState:UIControlStateNormal];
            [vc.tabBarItem setTitleTextAttributes:selectedAttributes.copy forState:UIControlStateSelected];
        }
        //设置 tabbar背景色
        [self.tabBar setBackgroundImage:bgImage];
        //设置 tabbar上边的一条灰线
        [self.tabBar setShadowImage:shadowImage];
    }
}

#pragma mark - 指定颜色和size生成图片
-(UIImage *)createImageForColor:(UIColor *)color withImageSize:(CGSize)size{
    
    CGRect rectBG = CGRectMake(0, 0, size.width, size.height);
    UIGraphicsBeginImageContext(rectBG.size);
    CGContextRef contextBG = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(contextBG, color.CGColor);
    CGContextFillRect(contextBG, rectBG);
    UIImage *imgBG = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return imgBG;
}

5.Xcode11 缺失库文件导入libstdc-6.0.9

libstdc-6.0.9 文件下载

一共四个文件夹, 按照README里写的添加, 需要注意的是第一个文件夹的位置由:
/Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/
【变更为】
/Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/

链接:https://www.jianshu.com/p/d2a0fa7bcbef

6.Xcode11新增SceneDelegate后如何更改window的根控制器, 并兼容iOS13以下的版本

Xcode新增SceneDelegate来管理window等生命周期, 如果需要更改window的默认根控制器, 需要在 SceneDelegate 中的
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions
代理方法中设置, 设置如下:

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
    
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[ViewController new]];
    nav.title = @"直播";
    UITabBarController *tabVC = [[UITabBarController alloc] init];
    tabVC.viewControllers = @[nav];
    
    self.window.rootViewController = tabVC;
    [self.window makeKeyAndVisible];
}

但是该方法只会在iOS13版本才执行, 如果是iOS13以下版本, 依然需要在 AppDelegate中的
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法中修改window的根控制器.

// 1. AppDelegate中添加window属性
@property (strong, nonatomic) UIWindow *window;

// 2.设置window的根控制器
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 13) {
        UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[ViewController new]];
        nav.title = @"直播";
        UITabBarController *tabVC = [[UITabBarController alloc] init];
        tabVC.viewControllers = @[nav];

        self.window.rootViewController = tabVC;
        [self.window makeKeyAndVisible];
    }
    
    return YES;
}

注意, 即使是iOS13以下版本, 也会执行 AppDelegate中的
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 代理, 所以一些第三方的权限验证还是可以部分版本全部写在这个代理方法中的.

6.1 使用SceneDelegate管理生命周期的风险: 使用UIAlertView闪退

https://blog.csdn.net/qq_18683985/article/details/104041447

6.2 iOS13不使用SceneDelegate

  1. 去掉info.plist 的Application Scene Manifest选项
  2. 对应的SceneDelegate删除掉。
  3. AppDelegate注释掉如下代理方法:
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options

- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions;
  1. AppDelegate添加如下代理方法:
-(void)applicationWillResignActive:(UIApplication *)application{
    NSLog(@"1");
}
-(void)applicationDidBecomeActive:(UIApplication *)application{
    NSLog(@"2");
}

- (void)applicationDidEnterBackground:(UIApplication *)application{
    NSLog(@"3");
}

-(void)applicationWillEnterForeground:(UIApplication *)application{
    NSLog(@"4");
}

-(void)applicationWillTerminate:(UIApplication *)application{
    NSLog(@"5");
}

-(void)applicationDidFinishLaunching:(UIApplication *)application{
    NSLog(@"6");
}

待续...

上一篇下一篇

猜你喜欢

热点阅读