ios13适配_ios13适配 屏幕旋转 - CSDN
精华内容
参与话题
  • iOS 13 适配 适配主要涉及的方面: UITextField 的私有属性 _placeholderLabel 被禁止访问了 控制器的 modalPresentationStyle 默认值变了 DarkMode 深色模式 MPMoviePlayerController 在iOS ...

    iOS 13 适配汇总

    iOS 13 支持适配的机型

    • iPhone X、iPhone XR、iPhone XS、iPhone XS Max
    • iPhone 8、iPhone 8 Plus
    • iPhone 7、iPhone 7 Plus
    • iPhone 6s、iPhone 6s Plus
    • iPhone SE
    • iPod touch (第七代)

    适配要求

    根据官网的说法,遵守以下要求的截止日期已延长至2020年6月30日。之后所有提交到 App Store 的 iPhone 和 iPad 应用必须使用 iOS 13 以上的 SDK 进行编译,并支持 iPhone Xs Max 或 12.9 寸 iPad Pro (3代) 及以后版本的全屏幕设计。

    适配主要涉及的方面:

    • API适配
    • 弃用
    • DarkMode 深色模式

    API适配

    本人正在积极地收集更多的iOS13适配的信息,随时更新

    一 、在 iOS 13 中部分私有方法 KVC 可能导致崩溃

    注意⚠️,iOS 13 通过 KVC 方式修改私有属性,有 Crush 风险,谨慎使用!
    

    崩溃信息

    *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Access to UISearchBar's _searchField ivar is prohibited. This is an application bug'	
    

    目前整理的会导致崩溃的私有 api 和对应替代方案如下:

    1. UITextField 的私有属性 _placeholderLabel 被禁止访问了

    收到的错误信息⚠️

    崩溃 api。获取 _placeholderLabel 不会崩溃,但是获取 _placeholderLabel 里的属性就会

    [_textField setValue:self.placeholderColor
    forKeyPath:@"_placeholderLabel.textColor"];
    [textField setValue:[UIFont systemFontOfSize:20] forKeyPath:@"_placeholderLabel.font"];
    

    解决方案:

    方案1:

    UITextField有个attributedPlaceholder的属性,我们可以自定义这个富文本来达到我们需要的结果。

    修改如下:

     NSMutableAttributedString *placeholderString =
     [[NSMutableAttributedString alloc] initWithString:placeholder
     attributes:@{NSForegroundColorAttributeName : self.placeholderColor}];
     _textField.attributedPlaceholder = placeholderString;
    

    或者

    textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"输入" attributes:@{
        NSForegroundColorAttributeName: [UIColor blueColor],
        NSFontAttributeName: [UIFont systemFontOfSize:20]
    }];
    

    方案2:

    去掉下划线,访问 placeholderLabel

    [textField setValue:[UIColor blueColor] forKeyPath:@"placeholderLabel.textColor"];
    [textField setValue:[UIFont systemFontOfSize:20] forKeyPath:@"placeholderLabel.font"];
    

    2. UISearchBar 的私有属性 _searchField 被禁止访问了

    崩溃 api

    UITextField *textField = [searchBar valueForKey:@"_searchField"];
    

    方案 1,使用 iOS 13 的新属性 searchTextField

    searchBar.searchTextField.placeholder = @"search";
    

    方案 2,遍历获取指定类型的属性

    - (UIView *)findViewWithClassName:(NSString *)className inView:(UIView *)view{
        Class specificView = NSClassFromString(className);
        if ([view isKindOfClass:specificView]) {
            return view;
        }
        
        if (view.subviews.count > 0) {
            for (UIView *subView in view.subviews) {
                UIView *targetView = [self findViewWithClassName:className inView:subView];
                if (targetView != nil) {
                    return targetView;
                }
            }
        }
        
        return nil;
    }
    // 调用方法
    UITextField *textField = [self findViewWithClassName:@"UITextField" inView:_searchBar];
    

    3. UISearchBar 的私有属性 _cancelButtonText 被禁止访问了

    崩溃 api

    [searchBar setValue:@"取消" forKey:@"_cancelButtonText"];
    

    方案,用同上的方法找到子类中 UIButton 类型的属性,然后设置其标题

    UIButton *cancelButton = [self findViewWithClassName:NSStringFromClass([UIButton class]) inView:searchBar];
    [cancelButton setTitle:@"取消" forState:UIControlStateNormal];
    

    二、 控制器的 modalPresentationStyle 默认值变了

    在iOS13中运行代码发现presentViewController和之前弹出的样式不一样。

    在这里插入图片描述

    会出现这种情况是主要是因为我们之前对UIViewController里面的一个属性,即modalPresentationStyle(该属性是控制器在模态视图时将要使用的样式)没有设置需要的类型。在iOS13中modalPresentationStyle的默认改为UIModalPresentationAutomatic,而在之前默认是UIModalPresentationFullScreen

    查阅了下 UIModalPresentationStyle枚举定义,赫然发现iOS 13

    新加了一个枚举值:

    typedef NS_ENUM(NSInteger, UIModalPresentationStyle) {
         UIModalPresentationFullScreen = 0,
         UIModalPresentationPageSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
        UIModalPresentationFormSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
         UIModalPresentationCurrentContext API_AVAILABLE(ios(3.2)),
         UIModalPresentationCustom API_AVAILABLE(ios(7.0)),
         UIModalPresentationOverFullScreen API_AVAILABLE(ios(8.0)),
         UIModalPresentationOverCurrentContext API_AVAILABLE(ios(8.0)),
         UIModalPresentationPopover API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(tvos),
         UIModalPresentationBlurOverFullScreen API_AVAILABLE(tvos(11.0)) API_UNAVAILABLE(ios) API_UNAVAILABLE(watchos),
         UIModalPresentationNone API_AVAILABLE(ios(7.0)) = -1,
        UIModalPresentationAutomatic API_AVAILABLE(ios(13.0)) = -2, };
    

    要改会原来模态视图样式,我们只需要把UIModalPresentationStyle设置为UIModalPresentationFullScreen即可。

    ⚠️注意:UIModalPresentationOverFullScreen最低支持iOS 8,如果你还要支持iOS 8以下版本,那么你可以用UIModalPresentationFullScreen,这个两个值的交互略有些细微差别,具体的可以自己看下效果。

       ViewController *vc = [[ViewController alloc] init];
             vc.title = @"presentVC";
             UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
             nav.modalPresentationStyle = UIModalPresentationFullScreen;
             [self.window.rootViewController presentViewController:nav animated:YES completion:nil];
    

    三、DeviceToken有变化

    一般现在的第三方推送都是将DeviceToken原始数据丢进去,具体的解析都是第三方内部处理,所以,这些第三方解析DeviceToken的方式正确的话,那就毫无问题。如果你们是通过直接将 NSData 类型的 deviceToken 转换成 NSString 字符串,然后替换掉多余的符号获取DeviceToken,那你需要注意了,如下:

     NSString *dt = [deviceToken description]; dt = [dt
     stringByReplacingOccurrencesOfString: @"<" withString: @""]; dt = [dt
     stringByReplacingOccurrencesOfString: @">" withString: @""]; dt = [dt
     stringByReplacingOccurrencesOfString: @" " withString: @""];
    

    这段代码运行在 iOS 13 上已经无法获取到准确的DeviceToken字符串了,iOS 13 通过[deviceToken description]获取到的内容已经变成了:

    {length = 32, bytes = 0xd7f9fe34 69be14d1 fa51be22 329ac80d ... 5ad13017 b8ad0736 }
    

    解决办法一

    NSMutableString *deviceTokenString = [NSMutableString string];
     const char *bytes = deviceToken.bytes;
     NSInteger count = deviceToken.length;
     for (int i = 0; i < count; i++) {
         [deviceTokenString appendFormat:@"%02x", bytes[i]&0x000000FF];
     }
    

    解决办法二

    或者你也可以使用极光提供的方法(2019年7月24日更新)

    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
     {
         if (![deviceToken isKindOfClass:[NSData class]]) return;
    const unsigned *tokenBytes = [deviceToken bytes];
         NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                               ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                              ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                               ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
         NSLog(@"deviceToken:%@",hexToken); }
    

    四、 Sign in with Apple

    (提供第三方登录的注意啦⚠️)

    在 iOS 13 中苹果推出一种在 App 和网站上快速、便捷登录的方式: Sign In With Apple。这是 iOS 13 新增的功能,因此需要使用 Xcode 11 进行开发。关于应用是否要求接入此登录方式,苹果在 App Store 应用审核指南 中提到:

    Apps that exclusively use a third-party or social login service (such
    as Facebook Login, Google Sign-In, Sign in with Twitter, Sign In with
    LinkedIn, Login with Amazon, or WeChat Login) to set up or
    authenticate the user’s primary account with the app must also offer
    Sign in with Apple as an equivalent option.

    如果你的应用使用了第三方或社交账号登录服务(如Facebook、Google、Twitter、LinkedIn、Amazon、微信等)来设置或验证用户的主账号,就必须把 Sign In With Apple 作为同等的选项添加到应用上。如果是下面这些类型的应用则不需要添加

    仅仅使用公司内部账号来注册和登录的应用;

    • 要求用户使用现有的教育或企业账号进行登录的教育、企业或商务类型的应用;

    • 使用政府或业界支持的公民身份识别系统或电子标识对用户进行身份验证的应用;

    • 特定第三方服务的应用,用户需要直接登录其邮箱、社交媒体或其他第三方帐户才能访问其内容。

    另外需要注意,关于何时要求接入 Sign In With Apple,苹果在 News and Updates 中提到:

    New apps must follow these guidelines starting April 30, 2020. App updates must follow these guidelines starting June 30, 2020.

    新的应用程序必须从2020年4月30日开始遵循这些指导原则。从2020年6月30日开始,应用程序更新必须遵循这些指导原则.

    五、即将废弃的 LaunchImage

    从 iOS 8 的时候,苹果就引入了 LaunchScreen,我们可以设置 LaunchScreen来作为启动页。当然,现在你还可以使用LaunchImage来设置启动图。不过使用LaunchImage的话,要求我们必须提供各种屏幕尺寸的启动图,来适配各种设备,随着苹果设备尺寸越来越多,这种方式显然不够 Flexible。而使用 LaunchScreen的话,情况会变的很简单, LaunchScreen是支持AutoLayout+SizeClass的,所以适配各种屏幕都不在话下。

    注意啦⚠️. 要求的截止日期已延长至2020年6月30日 . 从2020年6月30日开始,所有使⽤ iOS13 SDK的 App将必须提供 LaunchScreen,LaunchImage即将退出历史舞台。
    

    六、UIActivityIndicatorView加载视图

    iOS13对UIActivityIndicatorView的样式也做了修改
    之前有三种样式:

    • UIActivityIndicatorViewStyleGray 灰色
    • UIActivityIndicatorViewStyleWhite 白色
    • UIActivityIndicatorViewStyleWhiteLarge 白色(大型)

    iOS13废弃了以上三种样式,而用以下两种样式代替:

    • UIActivityIndicatorViewStyleLarge (大型)
    • UIActivityIndicatorViewStyleMedium (中型)

    iOS13通过color属性设置其颜色

    - (UIActivityIndicatorView *)loadingView {
        if (_loadingView == nil) {
            _loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleLarge];
            [_loadingView setColor:[UIColor systemBackgroundColor]];
            [_loadingView setFrame:CGRectMake(0, 0, 200, 200)];
            [_loadingView setCenter:self.view.center];
        }
        return _loadingView;
    }
    

    七、 UISearchBar 黑线处理导致崩溃

    之前为了处理搜索框的黑线问题,通常会遍历 searchBar 的 subViews,找到并删除 UISearchBarBackground。

    for (UIView *view in _searchBar.subviews.lastObject.subviews) {
        if ([view isKindOfClass:NSClassFromString(@"UISearchBarBackground")]) {
            [view removeFromSuperview];
            break;
        }
    }
    

    在 iOS13 中这么做会导致 UI 渲染失败,然后直接崩溃,崩溃信息如下:

    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Missing or detached view for search bar layout'
    

    解决方案

    设置 UISearchBarBackground 的 layer.contents 为 nil:

    for (UIView *view in _searchBar.subviews.lastObject.subviews) {
        if ([view isKindOfClass:NSClassFromString(@"UISearchBarBackground")]) {
            view.layer.contents = nil;
            break;
        }
    }
    

    八、UINavigationBar 设置按钮边距导致崩溃

    从 iOS 11 开始,UINavigationBar 使用了自动布局,左右两边的按钮到屏幕之间会有 16 或 20 的边距。

    image.png
    为了避免点击到间距的空白处没有响应,通常做法是:定义一个 UINavigationBar 子类,重写 layoutSubviews 方法,在此方法里遍历 subviews 获取 _UINavigationBarContentView,并将其 layoutMargins 设置为 UIEdgeInsetsZero。

    - (void)layoutSubviews {
        [super layoutSubviews];
        
        for (UIView *subview in self.subviews) {
            if ([NSStringFromClass([subview class]) containsString:@"_UINavigationBarContentView"]) {
                subview.layoutMargins = UIEdgeInsetsZero;
                break;
            }
        }
    }
    

    然而,这种做法在 iOS 13 中会导致崩溃,崩溃信息如下:

    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Client error attempting to change layout margins of a private view'
    

    解决方案

    使用设置 frame 的方式,让 _UINavigationBarContentView 向两边伸展,从而抵消两边的边距。

    - (void)layoutSubviews {
        [super layoutSubviews];
        
        for (UIView *subview in self.subviews) {
            if ([NSStringFromClass([subview class]) containsString:@"_UINavigationBarContentView"]) {
                if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {
                    UIEdgeInsets margins = subview.layoutMargins;
                    subview.frame = CGRectMake(-margins.left, -margins.top, margins.left + margins.right + subview.frame.size.width, margins.top + margins.bottom + subview.frame.size.height);
                } else {
                    subview.layoutMargins = UIEdgeInsetsZero;
                }
                break;
            }
        }
    }
    

    九、CNCopyCurrentNetworkInfo 使用要求更严格

    从 iOS 12 开始,CNCopyCurrentNetworkInfo 函数需要开启 Access WiFi Information 的功能后才会返回正确的值。在 iOS 13 中,这个函数的使用要求变得更严格,根据 CNCopyCurrentNetworkInfo 文档说明,应用还需要符合下列三项条件中的至少一项才能得到正确的值:

    • 使用 Core Location 的应用, 并获得定位服务权限。

    • 使用 NEHotspotConfiguration 来配置 WiFi 网络的应用。

    • 目前正处于启用状态的 VPN 应用。

    苹果作出这项改变主要为了保障用户的安全,因为根据 MAC 地址容易推算出用户当前所处的地理位置。同样,蓝牙设备也具有 MAC 地址,所以苹果也为蓝牙添加了新的权限

    解决方案

    根据应用需求,添加三项要求其中一项。可以选择第一项获取定位权限,因为添加的成本不会太大,只需要用户允许应用使用定位服务即可。

     - (NSString*) getWifiSsid {   if (@available(iOS 13.0, *)) {
         //用户明确拒绝,可以弹窗提示用户到设置中手动打开权限
         if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
           NSLog(@"User has explicitly denied authorization for this application, or location services are disabled in Settings.");
           //使用下面接口可以打开当前应用的设置页面
           //[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
           return nil;
         }
         CLLocationManager* cllocation = [[CLLocationManager alloc] init];
         if(![CLLocationManager locationServicesEnabled] || [CLLocationManager authorizationStatus] ==
     kCLAuthorizationStatusNotDetermined){
           //弹框提示用户是否开启位置权限
           [cllocation requestWhenInUseAuthorization];
           usleep(50);
           //递归等待用户选选择
           return [self getWifiSsidWithCallback:callback];
         }   }   NSString *wifiName = nil;   CFArrayRef wifiInterfaces = CNCopySupportedInterfaces();   if (!wifiInterfaces) {
         return nil;   }   NSArray *interfaces = (__bridge NSArray *)wifiInterfaces;   for (NSString *interfaceName in interfaces) {
         CFDictionaryRef dictRef = CNCopyCurrentNetworkInfo((__bridge CFStringRef)(interfaceName));
      
         if (dictRef) {
           NSDictionary *networkInfo = (__bridge NSDictionary *)dictRef;
           NSLog(@"network info -> %@", networkInfo);
           wifiName = [networkInfo objectForKey:(__bridge NSString *)kCNNetworkInfoKeySSID];
           CFRelease(dictRef);
         }   }   CFRelease(wifiInterfaces);   return wifiName; }
     
    

    打印:如下

    network info -> { BSSID = “44:dd:fb:43:91:ff”; SSID = “Asus_c039”;
    SSIDDATA = <41737573 5f633033 39>; } 不同意 network info -> { BSSID =
    “00:00:00:00:00:00”; SSID = WLAN; SSIDDATA = <574c414e>; }

    十、增加一直使用蓝牙的权限申请

    在 iOS 13 中,苹果将原来蓝牙申请权限用的 NSBluetoothPeripheralUsageDescription 字段,替换为 NSBluetoothAlwaysUsageDescription 字段。在info.plist里增加NSBluetoothAlwaysUsageDescription 我们要一直使用您的蓝牙

    如果在 iOS 13 中使用旧的权限字段获取蓝牙权限,会导致崩溃,崩溃信息如下:

    This app has crashed because it attempted to access privacy-sensitive data without a usage description.  The app's Info.plist must contain an NSBluetoothAlwaysUsageDescription key with a string value explaining to the user how the app uses this data.
    

    另外,如果将没有新字段的包提交审核,将会收到包含 ITMS-90683 的邮件,并提示审核不通过。

    解决方案

    官网文档也有说明,就是在 Info.plist 中把两个字段都加上。

    For deployment targets earlier than iOS 13, add both NSBluetoothAlwaysUsageDescription and NSBluetoothPeripheralUsageDescription to your app’s Information Property List file.
    

    十一、 iOS 13 不再支持 UIApplicationExitsOnSuspen

    发布到App Store时,出现以下错误:

    警告ITMS-90339:“已弃用的Info.plist密钥.Info.plist在bundle ar [ar.app]中包含一个密钥'UIApplicationExitsOnSuspend',很快就会不受支持。删除密钥,重建您的应用并重新提交。”
    

    解决方案

    从Info.plist中删除该密钥。

    这是一个小技巧。选择Info.plist。然后右键单击任何键或值,并选择“显示原始键/值”。如果UIApplicationExitsOnSuspend这个键是包括在内删除即可。

    十二、 获取SearchBar的cancleButton

    获取SearchBar的cancleButton,由于searcBar的层级发生变化以及对象的局部变量,因为无法通过kvc的方式来获取

    i

    f ([[[UIDevice currentDevice]systemVersion] floatValue] >= 13.0) {
    for(id cc in [self.searchBar subviews]) {
    for (id zz in [cc subviews]) {
    for (id gg in [zz subviews]) {
    if([gg isKindOfClass:[UIButton class]]){
    UIButton *cancelButton = (UIButton )gg;
    [cancelButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    }
    }
    } } }else{
    UIButton
    cancelButton = (UIButton *)[self.searchBar getVarWithName:@"_cancelButton"];
    [cancelButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; }

    十三、 UISegmentedControl 默认样式改变

    默认样式变为白底黑字,如果设置修改过颜色的话,页面需要修改。

    原本设置选中颜色的 tintColor 已经失效,新增了 selectedSegmentTintColor 属性用以修改选中的颜色。

    十四、使用MJExtension 中处理NSNull的不同

    这个直接会导致Crash的在将服务端数据字典转换为模型时,如果遇到服务端给的数据为NSNull时,
    mj_JSONObject,其中 class_copyPropertyList方法得到的属性里,多了一种EFSQLBinding类型的东西,而且属性数量也不准确,那就没办法了,只能改写这个方法了,这个组件没有更新的情况下,写了一个方法swizzling掉把当遇到 NSNull时,直接转为nil了。

    十五、 WKWebView 中测量页面内容高度的方

    OS 13以前
    document.body.scrollHeight
    iOS 13中
    document.documentElement.scrollHeight
    两者相差55 应该是浏览器定义高度变了
    

    十六、 状态栏(StatusBar)

    目前状态栏也增加了一种模式,由之前的两种,变成了三种, 其中default由之前的黑色内容,变成了会根据系统模式,自动选择当前展示lightContent还是darkContent

    我们在使用的时候,就可以重写preferredStatusBarStyleget方法:

    弃用

    UIWebView 将被禁止提交审核

    在 iOS 13 推出后,苹果在 UIWebView 的说明上将其支持的系统范围定格在了 iOS 2 ~ iOS 12。目前,如果开发者将包含 UIWebView api 的应用更新上传到 App Store 审核后,其将会收到包含 ITMS-90809 信息的回复邮件,提示你在下一次提交时将应用中 UIWebView 的 api 移除。

    Dear Developer,

    We identified one or more issues with a recent delivery for your app,
    “xxx”. Your delivery was successful, but you may wish to correct the
    following issues in your next delivery:

    ITMS-90809: Deprecated API Usage - Apple will stop accepting
    submissions of apps that use UIWebView APIs . See
    developer.apple.com/documentati… for more information.

    After you’ve corrected the issues, you can use Xcode or Application
    Loader to upload a new binary to App Store Connect.

    Best regards,

    The App Store Team

    解决方案

    WKWebView 替代 UIWebView,确保所有 UIWebView 的 api 都要移除,如果需要适配 iOS 7 的可以通过 openURL 的方式在 Safari 打开。

    备注:

    问题1: WKWebView 中拨打电话失效
    

    解决办法:遵循 WKNavigationDelegate代理
    实现代理方法- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler

    具体代码如下:

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
        NSURL *URL = navigationAction.request.URL;
        NSString *scheme = [URL scheme];
        if ([scheme isEqualToString:@"tel"]) {
            NSString *resourceSpecifier = [URL resourceSpecifier];
    //       也可以使用 NSString *callPhone = [NSString stringWithFormat:@"telprompt://%@", resourceSpecifier];
            NSString *callPhone = [NSString stringWithFormat:@"tel://%@", resourceSpecifier];
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:callPhone]];
    
        }
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    
    问题2: WKWebView 中和js进行交互
    

    解决办法 使用WebViewJavaScriptBridge完成H5和原生的交互(iOS、安卓)都可用,关于iOS原生和js 的交互我结合在项目中的实际应用写了文在这边,如果觉得不错记得给个赞哦–》iOS原生和js 的交互

    使用 UISearchDisplayController 导致崩溃

    iOS 8 之前,我们在 UITableView 上添加搜索框需要使用 UISearchBar + UISearchDisplayController 的组合方式,而在 iOS 8 之后,苹果就已经推出了 UISearchController 来代替这个组合方式。在 iOS 13 中,如果还继续使用 UISearchDisplayController 会直接导致崩溃,崩溃信息如下:

    *** Terminating app due to uncaught exception 'NSGenericException', reason: 'UISearchDisplayController is no longer supported when linking against this version of iOS. Please migrate your application to UISearchController

    解决方案

    使用 UISearchController 替换 UISearchBar + UISearchDisplayController 的组合方案。

    MPMoviePlayerController 在iOS 13中废弃

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'MPMoviePlayerController is no longer available. Use AVPlayerViewController in AVKit.'
    

    解决方案

     'MPMoviePlayerController is no longer available. Use
     AVPlayerViewController in AVKit.'
    

    方案就是AVKit里面的那套播放器

    Xcode 11 创建的工程在低版本设备上运行黑屏

    使用 Xcode 11 创建的工程,运行设备选择 iOS 13.0 以下的设备,运行应用时会出现黑屏。这是因为 Xcode 11 默认是会创建通过 UIScene 管理多个 UIWindow 的应用,工程中除了 AppDelegate 外会多一个 SceneDelegate:

    在这里插入图片描述
    这是为了 iPadOS 的多进程准备的,也就是说 UIWindow 不再是 UIApplication 中管理,但是旧版本根本没有 UIScene。

    解决方案

    在 AppDelegate 的头文件加上:

    @property (strong, nonatomic) UIWindow *window;
    

    使用 @available 导致旧版本 Xcode 编译出错

    在 Xcode 11 的 SDK 工程的代码里面使用了 @available 判断当前系统版本,打出来的包放在 Xcode 10 中编译,会出现一下错误:

    Undefine symbols for architecture i386:
        "__isPlatformVersionAtLeast", referenced from:
            ...
    ld: symbol(s) not found for architecture i386
    

    从错误信息来看,是 __isPlatformVersionAtLeast 方法没有具体的实现,但是工程里根本没有这个方法。实际测试无论在哪里使用@available ,并使用 Xcode 11 打包成动态库或静态库,把打包的库添加到 Xcode 10 中编译都会出现这个错误,因此可以判断是 iOS 13 的 @available 的实现中使用了新的 api

    解决方案

    如果你的 SDK 需要适配旧版本的 Xcode,那么需要避开此方法,通过获取系统版本来进行判断:

    if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {
        ...
    }
    

    另外,在 Xcode 10 上打开 SDK 工程也应该可以正常编译,这就需要加上编译宏进行处理:

    #ifndef __IPHONE_13_0
    #define __IPHONE_13_0 130000
    #endif
    
    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
    ...
    #endif
    

    DarkMode 深色模式

    • iOS 13 推出暗黑模式,UIKit 提供新的系统颜色和 api 来适配不同颜色模式,xcassets 对素材适配也做了调整,具体适配可见: Implementing Dark Mode on iOS

    在这里插入图片描述
    针对黑暗模式的推出,Apple官方推荐所有三方App尽快适配。目前并没有强制App进行黑暗模式适配。因此黑暗模式适配范围现在可采用以下三种策略:

    • 全局关闭黑暗模式

    • 指定页面关闭黑暗模式

    • 全局适配黑暗模式

    全局关闭黑暗模式

    如果不打算适配 Dark Mode,全局关闭黑暗模式,有两种方案:

    方案一:在项目 Info.plist 文件中,添加一条内容,Key为 User Interface Style,值类型设置为String并设置为 Light 即可。

    不过也有一点,在系统模式为深色模式的情况下,项目全局关闭黑暗模式,导航栏字体渲染色还是一直会是白色,需要特别设置。

    方案二:代码强制关闭黑暗模式,将当前 window 设置为 Light 状态。

    if(@available(iOS 13.0,*)){
    self.window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
    }
    

    即可在应用内禁用暗黑模式。

    不过即使设置了颜色方案,申请权限的系统弹窗还是会依据系统的颜色进行显示,自己创建的 UIAlertController 就不会。

    指定页面关闭黑暗模式

    从Xcode 11、iOS 13开始,UIViewController与View新增属性 overrideUserInterfaceStyle,若设置View对象该属性为指定模式,则强制该对象以及子对象以指定模式展示,不会跟随系统模式改变。

    • 设置 ViewController 该属性, 将会影响视图控制器的视图以及子视图控制器都采用该模式

    • 设置 View 该属性, 将会影响视图及其所有子视图采用该模式

    • 设置 Window 该属性, 将会影响窗口中的所有内容都采用该样式,包括根视图控制器和在该窗口中显示内容的所有控制器

    全局适配黑暗模式

    • 模拟器调试(simulator debug)
    • 图片(assets)
    • 颜色(color)

    模拟器调试

    • 运行项目
    • 点击Xcode底部调试栏中Environment Overrides
    • 开启Interface Style,就可以切换了。
      在这里插入图片描述

    在这里插入图片描述模拟器打开darkmode

    图片适配

    图片适配,主要是我们本地图片资源适配

    **方式1:
    图片适配比较方便的就是通过Assets.xcassets进行图片管理:

    • 添加一个image set,重命名如"adaptimage",
    • 选中该image set; 选中Attributes Inspector;
    • Appearances由"None“改为”Any,Dark";
    • 不同模式下设置不同图片即可,mode 改变会自动选择不同的图片
      在这里插入图片描述

    **方式2:
    你也可以直接使用判断当前系统mode的方式进行区分:

    需要监听系统模式的变化,重写UITraitEnvironment协议方法traitCollectionDidChange(_😃,我们先看下协议方法:

    public protocol UITraitEnvironment : NSObjectProtocol {
    
         @available(iOS 8.0, *)
         var traitCollection: UITraitCollection { get }
     
         /** To be overridden as needed to provide custom behavior when the environment's traits change. */
         @available(iOS 8.0, *)
         func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) }
    

    所以,我们只需要在改变系统mode的时候,重写代理:

     (void)traitCollectionDidChange:(UITraitCollection
     *)previousTraitCollection {
         [super traitCollectionDidChange:previousTraitCollection];
         
         // 对比情景改变
         BOOL isChanged = [traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection];
     }
    

    View 的 layoutSubView, ViewController 的 viewDidLayoutSubviews 均会触发 traitCollectionDidChange:方法

    颜色适配

    颜色适配有三种方式:

    方法一:是通过Assets.xcassets添加一个Color Set,目前系统支持≥iOS11.0

    在这里插入图片描述

    方法二:动态颜色

    动态颜色,根据当前情景自动切换颜色,iOS 13 新定义了一批 dynamic color, 大部分以 system 开头,也有以适用类别开头的,例如 labelColor,systemGroupedBackgroundColor,可以直接用
    1. 自定义 dynamic color
     // iOS 13 UIColor *dynamicColor = [UIColor
     colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection *
     _Nonnull traitC) {
             if (traitC.userInterfaceStyle == UIUserInterfaceStyleDark) {
                 return UIColor.redColor;
             } else {
                 return UIColor.greenColor;
             }
         }];
    
    1. 根据当前情景取出 dynamic color 中的色值----用于根据不同情景取色值,设置色值。
    UIColor *dynamicColor = [UIColor systemBackgroundColor];
     UITraitCollection *traitCollection = someView.traitCollection; UIColor
     *resolvedColor = [dynamicColor resolvedColorWithTraitCollection:traitCollection];
    

    本人正在积极地收集更多的iOS13适配的信息,随时更新

    展开全文
  • WWDC2019 ------iOS13适配(持续更新)

    千次阅读 2019-06-15 23:38:51
    第一、Web Content适配 https://developer.apple.com/videos/play/wwdc2019/511/ https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme 问题展示 先看两张图: 如上图所示,如果h5...

    第一、Web Content适配

    https://developer.apple.com/videos/play/wwdc2019/511/

    https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme

    问题展示

    先看两张图:

    如上图所示,如果h5未适配dark模式,则在dark模式下原来的页面内容展示就就存在问题。

    适配方法

    这里主要介绍基于CSS样式的修改来适配web内容

    首先,一定要声明当前支持的color-scheme有两种样式,这一句很重要,用东北话说就是“必须的”

    :root {
        color-scheme: light dark;
    }

    适配的策略就是为两种color-scheme设置不同的颜色样式。

    1、文本适配

    如图一,它的CSS描述为

     body {
         color: black;
     }
     h1 {
         color: #333;
     }
     .header {
        background-color: #593a78;
        color: white;
     }

    这里相关的颜色样式都是写死的,所以dark模式下才会出现图二的情况。现在我们来看如何适配下面这段代码:

    
    h1 {
        color: #333;
    }
    .header {
        background-color: #593a78;
        color: white;
    }

    然后可用如下方式改造:

    :root {
        color-scheme: light dark; 
        --post-title-color: #333;
        --header-bg-color: #593a78;
        --header-txt-color: white;
    }
    
    
    h1 {
        color: var(--post-title-color);
    }
    .header {
        background-color: var(--header-bg-color);
        color: var(--header-txt-color);
    }

    这里所做的工作实际上是抽象了颜色的值的setter和getter,即不同模式下的值统一定义,然后使用时通过var()去自动获取。

    而结合@media与prefers-color-scheme,颜色值的定义可以更加清晰:

    @media (prefers-color-scheme: dark) {
        :root {
            --post-title-color: white;
            --header-bg-color: #513d66;
            --header-txt-color: #eee;
        }
    }

    同理可以定义light模式下的色值。

    2、图片适配

    假设原文件有一幅图片资源,其CSS描述如下:

    <img src="mojave-day.jpg">

    那么,可以通过下面的方式来达到适配两种模式的目的:

    <picture>
        <source srcset="mojave-night.jpg" media="(prefers-color-scheme: dark)">
        <img src="mojave-day.jpg">
    </picture>

    3、动态内容适配

    动态内容适配需要注意:WebKit提供了获取指定模式下需要适配的多媒体项的能力,以及不同模式间切换的通知,一般情况下,通过下面的方式可以完成适配:

    // Adapting dynamic content to dark mode with JavaScript
    let darkModeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
    function updateForDarkModeChange() {
        if (darkModeMediaQuery.matches) {
            ...
        } else {
            ...
        }
    }
    darkModeMediaQuery.addListener(updateForDarkModeChange);
    updateForDarkModeChange(); // Handle if Dark Mode is already active.

    所以,这里很显然要处理light2dark和dark2light等情形。   

    如果需要更深度的定制,需h5与客户端评估是否需要注入js变量来判断当前模式。如果涉及服务端的直接适配,则可考虑在UA中添加识别信息。

    4、小结:

    • 使用 color-scheme 来声明支持的模式;
    • 利用prefers-color-scheme来设置不同模式下的配置;
    • 利用<picture> 标签设置不同模式下的图片;
    • 利用var() 方法来适配不同模式下的变量取值;
    • 动态内容适配视具体情况而定。

     

    展开全文
  • iOS13 适配总结

    千次阅读 2019-11-14 14:53:20
    1、UISegmentedControl 修改选择背景色 if (@available(iOS 13.0, *)) { _segmented.selectedSegmentTintColor = Stock_Red; } else { _segmented.tintColor = Stock_Red; }

    1、UISegmentedControl 修改选择背景色

           if (@available(iOS 13.0, *)) {
                _segmented.selectedSegmentTintColor = Stock_Red;
            } else {
                _segmented.tintColor = Stock_Red;
            }
    // 以下代码可以代替上面:
       [_segmented setBackgroundImage:[UIImage imageWithColor:[UIColor clearColor]] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
       [_segmented setBackgroundImage:[UIImage imageWithColor:Stock_Red] forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
    
    // [UIImage imageWithColor:xx]
    // 这是我自己封装的方法:返回一张纯色图片 
    + (UIImage *)imageWithColor:(UIColor *)color {
        CGRect rect = CGRectMake(0, 0, 1, 1);
        UIGraphicsBeginImageContext(rect.size);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetFillColorWithColor(context, [color CGColor]);
        CGContextFillRect(context, rect);
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return image;
    }
    
    



    2、模态视图样式

    代码块语法遵循标准markdown代码,例如:

    要改回原来模态视图样式,我们只需要把UIModalPresentationStyle设置为UIModalPresentationFullScreen即可。
    
    ViewController *vc = [[ViewController alloc] init];
    vc.title = @"presentVC";
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
    nav.modalPresentationStyle = UIModalPresentationFullScreen;
    [self.window.rootViewController presentViewController:nav animated:YES completion:nil];
    



    3、私有KVC

    在使用iOS 13运行项目时突然APP就crash掉了。定位到的问题是在设置UITextField的Placeholder也就是占位文本的颜色和字体时使用了KVC的方法:

    [_textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
    [_textField setValue:[UIFont systemFontOfSize:14] forKeyPath:@"_placeholderLabel.font"];
    

    可以将其替换为:

    _textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"文本" attributes:@{
    NSFontAttributeName:[UIFont systemFontOfSize:16],
    NSForegroundColorAttributeName:[UIColor redColor]}];
    

    并且只需要在初始化的时候设置attributedPlaceholder即富文本的占位文本,再重新赋值依然使用placeolder直接设置文本内容,样式不会改变。



    4、黑暗模式

    取消黑暗模式
    在 plist 文件中添加一下键值对:
    UIUserInterfaceStyle Light
    在这里插入图片描述



    5、iOS13 屏幕旋转

    这里 ViewController 简称:VC
    iOS13以前的 API (在iOS13中失效了),以前在进入ViewController 时可以自动调用,现在不调用了

    @interface xxViewController
    
    @end
    
    @implementation xxViewController
    
    // 原需求:屏幕锁定,不支持屏幕旋转,手动让VC横屏    
    #pragma mark - Orientation是否支持转屏
    - (BOOL)shouldAutorotate{
        return NO;
    }
    #pragma mark - 支持哪些转屏方向
    - (UIInterfaceOrientationMask)supportedInterfaceOrientations{
        if (self.isBack) {
            return UIInterfaceOrientationMaskPortrait;
        }else {
            return UIInterfaceOrientationMaskLandscapeRight;
        }
    }
    #pragma mark - 默认的屏幕方向
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
        return UIInterfaceOrientationLandscapeRight;
    }
    @end
    

    iOS 13 中的解决方案

    //-----------------------"  AppDelegate  "-----------------------
    #import <UIKit/UIKit.h>
    #import <CoreData/CoreData.h>
    + (AppDelegate *)shareInstance;
    // 旋转屏幕 
    -(void)changeOrientation:(UIInterfaceOrientation)toOrientation;
    @end
    
    
    #import "AppDelegate.h"
    @interface AppDelegate () 
    @end
    
    @implementation AppDelegate
    
    static AppDelegate *_singleInstance;
    +(AppDelegate *)shareInstance {
        return _singleInstance;
    }
    - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
    {
        if(self.allowRotation) {
            return UIInterfaceOrientationMaskLandscape;
        } else {
            return UIInterfaceOrientationMaskPortrait;
        }
    }
    //要解决很简单,只需要在方法函数头部添加几句不会被编译器优化掉的代码即可。
    #pragma mark - 旋转屏幕
    -(void)changeOrientation:(UIInterfaceOrientation)toOrientation {
        NSLog(@"---旋转屏幕= %ld",(long)toOrientation);
      if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
            SEL selector = NSSelectorFromString(@"setOrientation:");
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
            [invocation setSelector:selector];
            [invocation setTarget:[UIDevice currentDevice]];
          
          int val = 0;
          if (toOrientation==UIInterfaceOrientationPortrait) {
              val = UIInterfaceOrientationPortrait;
              
          }else if (toOrientation==UIInterfaceOrientationPortraitUpsideDown){
              val = UIInterfaceOrientationPortraitUpsideDown;
              
          }else if (toOrientation==UIInterfaceOrientationLandscapeLeft){
              val = UIInterfaceOrientationLandscapeRight;
              
          }else if (toOrientation==UIInterfaceOrientationLandscapeRight){
              val = UIInterfaceOrientationLandscapeLeft;
          }
            [invocation setArgument:&val atIndex:2];
            [invocation invoke];
        }
    }
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
     
        //1.AppDelegate
        _singleInstance = self;
        self.application = application;
        return YES;
    }
    @end
    
    //-----------------------"  xxViewController  "-----------------------
    interface xxViewController
    
    @end
    
    @implementation xxViewController
    
    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        [AppDelegate shareInstance].allowRotation = YES;
        [[AppDelegate shareInstance] changeOrientation:UIInterfaceOrientationLandscapeLeft];
    }
    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        [AppDelegate shareInstance].allowRotation = NO;
         [[AppDelegate shareInstance] changeOrientation:UIInterfaceOrientationPortrait];
    }
    @end
    
    



    6、iOS13 新增编辑手势

    复制:三指捏合
    剪切:两次三指捏合
    粘贴:三指松开
    撤销:三指向左划动(或三指双击)
    重做:三指向右划动
    快捷菜单:三指单击

    // 暂时禁用

    #ifdef __IPHONE_13_0
    - (UIEditingInteractionConfiguration)editingInteractionConfiguration{
        return UIEditingInteractionConfigurationNone;
    }
    #endif
    



    7、iOS13 新生命周期 SceneDelegate

    增加了 #import "SceneDelegate.h"
    原来的 #import "AppDelegate.h" 没有了window

    要想维持原状,需要在AppDelegate里,添加window,并且删掉Info.plist里的新增键值对
    @property (strong, nonatomic) UIWindow *window;

    @interface AppDelegate : UIResponder
    @property (strong, nonatomic) UIWindow *window;
    @end
    删掉以下键值对
    Application Scene Manifest:2times
    Main storyboard file base name:Main

    在这里插入图片描述


    更新中·····

    「文章有不对地方,欢迎批评指正!」
    展开全文
  • iOS 13 适配 (填坑...)

    万次阅读 2019-09-29 10:32:30
    iOS13中通过KVC方式来获取私有属性,有Carsh风险,尽量避免使用.比如我们常用的UITextFiled和UISearchController等,在iOS 13的searchbar添加了一个- (void)set_cancelButtonText:(NSString *)text方法,这个方法专门...

    1.私有API被封禁(KVC限制),禁止访问.

    iOS13中通过KVC方式来获取私有属性,有Carsh风险,尽量避免使用.比如我们常用的UITextFiled和UISearchController等,在iOS 13的searchbar添加了一个- (void)set_cancelButtonText:(NSString *)text方法,这个方法专门用来命中kvc,一旦命中就Crash。

    
    //修改textField的占位符字体颜色
    [textField setValue:[UIColor xxx] forKeyPath:@"_placeholderLabel.textColor"];
    
    

    (1).获取SearchBar的textField

    由于在13中把SearchBar中的textField直接暴露给开发者使用,无需在通过kvc获取。

    
    - (UITextField *)sa_GetSearchTextFiled{
        if ([[[UIDevice currentDevice]systemVersion] floatValue] >= 13.0) {
            return self.searchTextField;
        }else{
            UITextField *searchTextField =  [self valueForKey:@"_searchField"];
            return searchTextField;
        }
    }
    
    

    (2).修改TextFiled的占位符字体大小以及颜色,在iOS13中不能通过KVC来进行修改,可以通过其属性字符串来进行修改

    UITextField *textfield = [[UITextField alloc]init];
    NSMutableAttributedString *arrStr = [[NSMutableAttributedString alloc]initWithString:textfield.placeholder attributes:@{NSForegroundColorAttributeName : [UIColor redColor],NSFontAttributeName:[UIFont systemFontOfSize:12]}];
    textfield.attributedPlaceholder = arrStr;
    
    
    
    

    (3).获取SearchBar的cancleButton,由于searcBar的层级发生变化以及对象的局部变量,因为无法通过kvc的方式来获取

    
    if ([[[UIDevice currentDevice]systemVersion] floatValue] >= 13.0) {
              for(id cc in [self.searchBar subviews]) {
                  for (id zz in [cc subviews]) {
                      for (id gg in [zz subviews]) {
                          if([gg isKindOfClass:[UIButton class]]){
                              UIButton *cancelButton = (UIButton *)gg;
                              [cancelButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
                          }
                      }
                  }
    
              }
          }else{
              UIButton*cancelButton = (UIButton *)[self.searchBar getVarWithName:@"_cancelButton"];
              [cancelButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
          }
    
    
    
    

    2.MPMoviePlayerController在iOS13中废弃

    MPMoviePlayerController is no longer available. Use AVPlayerViewController in AVKit.
    在iOS13中对于MPMoviePlayerController使用的废弃,需要使用AVKit中的AVPlayerViewController来达到播放的目的。

    3.Sign in with Apple 第三方登录

    当 Sign In with Apple 服务正式上线以后,所有已接入其它第三方登录的 App,Sign In with Apple 将被要求作为一种登录选择,否则有可能就不给过。如果 APP 支持三方登陆(Facbook、Google、微信、QQ、支付宝等),就必须支持苹果登录,且要放前边。解决方法:未来上线之后,添加登录入口即可。

    4.即将废弃的 LaunchImage

    从 iOS 8 的时候,苹果就引入了 LaunchScreen,我们可以设置 LaunchScreen来作为启动页。当然,现在你还可以使用LaunchImage来设置启动图。不过使用LaunchImage的话,要求我们必须提供各种屏幕尺寸的启动图,来适配各种设备,随着苹果设备尺寸越来越多,这种方式显然不够 Flexible。而使用 LaunchScreen的话,情况会变的很简单, LaunchScreen是支持AutoLayout+SizeClass的,所以适配各种屏幕都不在话下。⚠️从2020年4月开始,所有使⽤ iOS13 SDK的 App将必须提供 LaunchScreen,LaunchImage即将退出历史舞台。可以使用Launch Storyboards来进行解决。

    5.模态弹出默认交互改变

    iOS 13 的 presentViewController 默认有视差效果,模态出来的界面现在默认都下滑返回。 一些页面必须要点确认才能消失的,需要适配。如果项目中页面高度全部是屏幕尺寸,那么多出来的导航高度会出现问题。

    
    // Swift
    self.modalPresentationStyle = .fullScreen
    // Objective-C
    self.modalPresentationStyle = UIModalPresentationFullScreen;
    

    UIViewController 增加一个了属性 isModalInPresentation,默认为 false,当该属性为 false 时,用户下拉可以 dismiss 控制器,为 true 时,下拉不可以 dismiss控制器。

    6.UISegmentedControl 默认样式改变

    默认样式变为白底黑字,如果设置修改过颜色的话,页面需要修改

    7.增加一直使用蓝牙的权限申请

    CBCentralManager,iOS13以前,使用蓝牙时可以直接用,不会出现权限提示,iOS13后,再使用就会提示了。在info.plist里增加NSBluetoothAlwaysUsageDescription 我们要一直使用您的蓝牙,具体做什么别问我

    8.废弃 UISearchDisplayController

    在 iOS 8 之前,我们在 UITableView 上添加搜索框需要使用 UISearchBar + UISearchDisplayController 的组合方式,而在 iOS 8 之后,苹果就已经推出了 UISearchController 来代替这个组合方式。在 iOS 13 中,如果还继续使用 UISearchDisplayController 会直接导致崩溃,

    9.修改StatusBar的颜色

    创建一个 UIView *_statusBar;
    在页面消失时置位nil,不影响其他页面。
    - (void)viewWillDisappear:(BOOL)animated {
     [super viewWillDisappear:animated];
     if (@available(iOS 13.0, *)) {
         [_statusBar removeFromSuperview];
         _statusBar = nil;
     }
    }
    
    
    if (@available(iOS 13.0, *)) {
         if (!_statusBar) {
             _statusBar = [[UIView alloc] initWithFrame:[UIApplication sharedApplication].statusBarFrame];
             [[UIApplication sharedApplication].keyWindow addSubview:_statusBar];
         }
    
     } else {
         
       _statusBar = [[[UIApplication sharedApplication] valueForKey:@"statusBarWindow"] valueForKey:@"statusBar"];
    }
     
    
     if ([_statusBar respondsToSelector:@selector(setBackgroundColor:)]) {
         _statusBar.backgroundColor = color;
     }
    

    未完待续…

    展开全文
  • I、 适配第三方库在iOS13的问题: 1.1) : 升级腾讯的第三方UI框架,解决iOS13 无法访问私有属性的问题 II、 适配iOS13UI控件的API :(涉及的模块有登录) 2.1)UITextField的_placeholderLabel属性:无法直接访问_...
  • iOS 13适配汇总

    千次阅读 2019-09-28 19:13:51
    随着iPhone 11的发布,iOS 13适配也提上了日程,接下来就开发中升级iOS13的手机可能出现的问题 Xcode: 11.0 iOS : 13.0 UIViewController 模态弹出界面 viewController.present(presentVC, animated: true, ...
  • IOS学习笔记56-IOS7状态栏适配方法一

    万次阅读 2013-10-11 12:07:06
    近期由于IOS7的发布,所以应用的适配潮可谓是都搞的锣鼓喧天,甚是热闹,因此呢,因适配IOS7而产生的问题也是铺天盖地的卷来,所以了,我也从简单的状态栏适配开始,先研究了下关于状态栏的适配,特总结如下,供广大...
  • 怎么做一个能同时适配iPhone和iPad的APP,两套xib共用一套代码,xcode用的是最新的xcode7
  • iOS 13 黑暗模式总结探索 暗黑模式苹果开发文档 如何不进行系统切换样式的适配 注意 同一工程内多个Assets文件在打包后,就会生成一个Assets.car 文件,所以要保证Assets内资源文件的名字不能相同 苹果官方...
  • 关于iOS 各个iPhone 尺寸图标的适配

    千次阅读 2016-07-25 19:54:48
    最标准的适配方式因该是UI切三套图,图标分别以 *.png *2@x.png *3@x.png命名,程序运行会自动选取对应的图片。 指的注意的是当某个倍数的图标缺失时,会选择其他倍数的图标代替,这样就会造成iPhone的适配问题。...
  • 这个东西好像出来之后 我QQ群里面iOS开发的很多人都炸了.确实这个齐刘海对我们开发者很不友好,往上xib的项目适配文章已经有了,但是还没有特别好的纯代码工程的适配.今天我就抛砖引玉,简单说一下我的纯代码工程是如何...
  • 在应用中如何用纯代码适配不同的iPhone设备,有没有好的方法?
  • IOS11 适配遇到的坑

    万次阅读 2017-09-19 10:07:55
    IOS11正式版马上就要发布了,是时候适配一波了。下面就来说说我适配过程中遇到的坑吧。UITableView:默认开启Self-Sizing 首先要知道Self-Sizing是个什么东东。看官方文档的解释: 大概就是说我们不再需要...
  • IPad Pro 12.9英寸版本的界面适配

    千次阅读 2017-08-20 22:37:55
    IOS开发怎么样适配12.9英寸的Pad Pro12.9英寸的iPad pro,宽高是(1366*1024),Pad其他版本都是(1024*768),按普通尺寸开发的pad应用,最后需要兼容一下pro。为此我自己写了三个宏。应该写在公共文件中#define ...
  • iOS iPhoneX-WebView适配问题

    千次阅读 2018-05-19 09:37:34
    iOS11之后引入了安全区域的概念,对此的影响主要表现在scroview的子类,但是在适配安全区域的时候发现了一些不科学的现象。 安全区域适配 if (@available(ios 11.0,*)) { UIScrollView.appearance....
  • 在苹果推出iPhone6Plus后,苹果的机型增多,显示屏的大小也变得多样,因此之前的绝对布局的方法难以满足手机的适配问题,因此苹果推出了相对布局的界面适配方法,本文所讲的界面适配方法主要基于Masnory的适配方法,...
  • 随着苹果iOS13系统即将发布,个推提前推出DeviceToken适配方案,以确保新版本的兼容与APP推送服务的正常使用。iOS13的一个重要变化是"[deviceToken description]" 会受不同运行环境及系统的影响而发生变化,如果未...
  • MJRefresh适配ios11以及iPhoneX

    千次阅读 2017-09-27 19:18:39
    这里写链接内容虽然还没钱买iPhone8和iPhoneX,但是新版的Xcode9已经有相关模拟器了,一打开模拟器惊呆了,那些自定义...其中iOS 11 安全区域适配总结这篇文章写得很是详细大多数文章提供的解决方案都是直接将新增属
  • 今天的 WWDC 19 上发布了 iOS 13,我们来看下如何适配 DarkMode 首先我们来看下效果图 如何适配 DarkMode DarkMode 主要从两个方面来适配,一是颜色,二是图片,适配的代码不是很多,接下来让我们一起来看看具体是...
  • IOS界面适配一: Pt与Px的关系

    万次阅读 2015-08-12 15:13:23
    参考链接 : iPhone屏幕尺寸、分辨率及适配    在IOS界面开发中,我们一般是使用pt(Point)来作为View的单位,它是一个标准的长度单位,1pt=1/72英寸  而px即为我们所说的像素,虽然我们使用的是pt,但是其最后...
1 2 3 4 5 ... 20
收藏数 44,352
精华内容 17,740
关键字:

ios13适配