iOS - 適配 iOS 13 之工兵連掃雷

iOS 13 支持適配的機型

目前最新 iPhone 十一、iPhone 11 Pro和iPhone 11 Pro Maxphp

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

適配要求
Starting April, 2020, all iPhone and iPad apps submitted to the App Store will need to be built with the iOS 13 SDK or later. They must also support the all-screen design of iPhone XS Max or the 12.9-inch iPad Pro (3rd generation), or later.ios

根據官網的說法,2020年4月以後全部提交到 App Store 的 iPhone 和 iPad 應用必須使用 iOS 13 以上的 SDK 進行編譯,並支持 iPhone Xs Max 或 12.9 寸 iPad Pro (3代) 及之後版本的全屏幕設計。

git

1、UI層面

注:必須適配的點以「(必須)」標出,這個必須有的點是必定要作的,有的是看我的項目,你們可忽略

1.Dark Mode

iOS 13 推出暗黑模式,UIKit 提供新的系統顏色和 api 來適配不一樣顏色模式,xcassets 對素材適配也作了調整,官方具體適配可見: Implementing Dark Mode on iOS
適配方案:github

若是不打算適配 Dark Mode,能夠直接在 Info.plist 中添加一欄:User Interface Style : Light,便可在應用內禁用暗黑模式。不過即便設置了顏色方案,申請權限的系統彈窗仍是會依據系統的顏色進行顯示,本身建立的 UIAlertController 就不會。

web

參考連接:
https://mp.weixin.qq.com/s/qliFbqRdkkE30vslojfJCA
https://juejin.im/post/5cf6276be51d455a68490b26json

2.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。目前蘋果只在 News and Updates 上提到正式發佈時要求加上,具體發佈時間還沒肯定。swift

Sign In with Apple  具體理解:
在 iOS 13 中蘋果推出一種在 App 和網站上快速、便捷登陸的方式: Sign In With Apple。這是 iOS 13 新增的功能,所以須要使用 Xcode 11 進行開發。關於應用是否要求接入此登陸方式,蘋果在 App Store 應用審覈指南 中提到:api

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.xcode

若是你的應用使用了第三方或社交帳號登陸服務(如Facebook、Google、Twitter、LinkedIn、Amazon、微信等)來設置或驗證用戶的主帳號,就必須把 Sign In With Apple 做爲同等的選項添加到應用上。若是是下面這些類型的應用則不須要添加:

僅僅使用公司內部帳號來註冊和登陸的應用;

要求用戶使用現有的教育或企業帳號進行登陸的教育、企業或商務類型的應用;

使用政府或業界支持的公民身份識別系統或電子標識對用戶進行身份驗證的應用;

特定第三方服務的應用,用戶須要直接登陸其郵箱、社交媒體或其餘第三方賬戶才能訪問其內容。

另外須要注意,關於什麼時候要求接入 Sign In With Apple,蘋果在 News and Updates 中提到:

Starting today, new apps submitted to the App Store must follow these guidelines. Existing apps and app updates must follow them by April 2020.

2019 年 9 月 12 日 起,提交到 App Store 的新應用必須按照應用審覈指南中的標準進行接入;現有應用和應用更新必須也在 2020 年 4 月前完成接入。

3.模態彈出默認交互改變(必須)

在 iOS 13 中此枚舉值直接成爲了模態彈出的默認值,所以 presentViewController 方式打開視圖是以下的視差效果,默認是下滑返回。

 
image

iOS13下仍然能夠作到全屏彈出,這裏須要UI決定採用哪一種樣式

4.UISegmentedControl 默認樣式改變(必須)

默認樣式變爲白底黑字,若是設置修改過顏色的話,頁面須要修改。

 
image

本來設置選中顏色的 tintColor 已經失效,新增了 selectedSegmentTintColor 屬性用以修改選中的顏色。
Web Content適配

5.h5的適配,參考連接:

https://blog.csdn.net/u012413955/article/details/92198556

2、代碼層面

1.私有方法 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]}];

  

 

解決方案二:去掉keypath中的「_」
若是須要修改UISearchBar的placeholder,須要獲取其searchTextField,可用category實現:

@implementation UISearchBar (SearchTextField)

- (UITextField *)atu_searchTextField{
    if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {
        //判斷xcode版本
#ifdef __IPHONE_13_0
        return self.searchTextField;
#else
        return [self valueForKey:@"searchTextField"];
#endif
    }

    //嘗試過遍歷subviews來找到,可是subviews中並不包含searchField!沒有找到更好的辦法
    return [self valueForKey:@"searchField"];
}

@end

  

若是有哪位大大有更好的辦法,請告知

2.推送的 deviceToken 獲取到的格式發生變化(必須)

本來能夠直接將 NSData 類型的 deviceToken 轉換成 NSString 字符串,而後替換掉多餘的符號便可:

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSString *token = [deviceToken description];
    for (NSString *symbol in @[@" ", @"<", @">", @"-"]) {
        token = [token stringByReplacingOccurrencesOfString:symbol withString:@""];
    }
    NSLog(@"deviceToken:%@", token);
}

  


在 iOS 13 中,這種方法已經失效,NSData類型的 deviceToken 轉換成的字符串變成了:

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

須要進行一次數據格式處理,參考友盟的作法,能夠適配新舊系統,獲取方式以下:

#include <arpa/inet.h>
- (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);
}

  

3.UISearchBar 黑線處理致使崩潰

以前爲了處理搜索框的黑線問題,一般會遍歷 searchBar 的 subViews,找到並刪除 UISearchBarBackground,在 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 removeFromSuperview];
        view.layer.contents = nil;
        break;
    }
}

  

4.使用 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.' 

另外說一下,在 iOS 13 中終於能夠獲取直接獲取搜索的文本框:

_searchBar.searchTextField.text = @「search";

 

5.模態彈出默認交互改變(必須)

若是須要作成全屏顯示的界面,須要手動設置彈出樣式:

- (UIModalPresentationStyle)modalPresentationStyle {
    return UIModalPresentationFullScreen;
} 
//或者在present以前:
ctr.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:ctr animated:animated completion:completion];

  

若是項目裏面有大量的位置使用了presentViewController,而後你不想每一個位置都顯式的手動修改,推薦這篇文章https://juejin.im/post/5d5f96866fb9a06b0517f78c
裏面的方法,原理是:

經過runtime修改ctr.modalPresentationStyle的默認值爲UIModalPresentationFullScreen(原默認值爲UIModalPresentationPageSheet)若是須要禁止自動修改默認值
ctr.LL_automaticallySetModalPresentationStyle = NO;

  

固然,若是有精力,不太多的話仍是建議老老實實的一個個手動修改,以避免之後官方api再次變更。

有一點注意的是,ctr的生命週期方法調用狀況會改變,假設有a,b兩個ctr,在a中present出b:

全屏present時(UIModalPresentationFullScreen)的方法調用順序:

a---viewWillDisappear:
b---viewWillAppear:
b---viewDidAppear:
a---viewDidDisappear:

dissmiss時的方法調用順序:

b---viewWillDisappear:
a---viewWillAppear:
a---viewDidAppear:
b---viewDidDisappear:

非全屏presnet時(UIModalPresentationPageSheet)的方法調用順序:

b---viewWillAppear:
b---viewDidAppear:

dissmiss時的方法調用順序:

b---viewWillDisappear:
b---viewDidDisappear:

能夠看出,以UIModalPresentationPageSheet的方式來present/dismiss時,分別少調用了a的兩個方法,若是以前在這個位置有相關的邏輯代碼,好比網絡請求,UI刷新,要注意

6.MPMoviePlayerController 被棄用

在 iOS 9 以前播放視頻可使用 MediaPlayer.framework 中的MPMoviePlayerController類來完成,它支持本地視頻和網絡視頻播放。可是在 iOS 9 開始被棄用,若是在 iOS 13 中繼續使用的話會直接拋出異常:

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

解決方案是使用 AVFoundation 裏的 AVPlayer。

7.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 進行審批。

8.Xcode 11 建立的工程在低版本設備上運行黑屏

使用 Xcode 11 建立的工程,運行設備選擇 iOS 13.0 如下的設備,運行應用時會出現黑屏。這是由於 Xcode 11 默認是會建立經過 UIScene 管理多個 UIWindow 的應用,工程中除了 AppDelegate 外會多一個 SceneDelegate.

 

這是爲了 iPadOS 的多進程準備的,也就是說 UIWindow 再也不是 UIApplication 中管理。可是舊版本根本沒有 UIScene,所以解決方案就是在 AppDelegate 的頭文件加上:

@property (strong, nonatomic) UIWindow *window; 

9.使用 @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 

10.textfield.leftview(必須)

以下方式,直接給 textfield.leftView 賦值一個 UILabel 對象,他的寬高會被 sizeToFit,而不是建立時的值。

// left view label
UILabel *phoneLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 63, 50)];
phoneLabel.text = @"手機號";
phoneLabel.font = [UIFont systemFontOfSize:16];
// set textfield left view
self.textfieldName.leftView = phoneLabel;

  

如所看到,實際leftview的width爲59,height爲19:

 
 

解決方法:嵌套一個UIView

// label
UILabel *phoneLabel = [[UILabel alloc] init];
phoneLabel.text = @"手機號";
phoneLabel.font = [UIFont systemFontOfSize:16];
[phoneLabel sizeToFit];
phoneLabel.centerY = 50/2.f;
// left view
UIView *leftView = [[UIView alloc] initWithFrame:(CGRect){0, 0, 63, 50}];
[leftView addSubview:phoneLabel];
// set textfield left view
self.textfieldName.leftView = leftView;

  

11.NSAttributedString優化

對於UILabel、UITextField、UITextView,在設置NSAttributedString時也要考慮適配Dark Mode,不然在切換模式時會與背景色融合,形成很差的體驗
不建議的作法

NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:16]};
NSAttributedString *str = [[NSAttributedString alloc] initWithString:@"富文本文案" attributes:dic];

  

推薦的作法

// 添加一個NSForegroundColorAttributeName屬性
NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor labelColor]};
NSAttributedString *str = [[NSAttributedString alloc] initWithString:@"富文本文案" attributes:dic];

  

12.TabBar紅點偏移

若是以前有經過TabBar上圖片位置來設置紅點位置,在iOS13上會發現顯示位置都在最左邊去了。遍歷UITabBarButton的subViews發現只有在TabBar選中狀態下才能取到UITabBarSwappableImageView,解決辦法是修改成經過UITabBarButton的位置來設置紅點的frame

13.廢棄UIWebView(必須)

UIWebView在12.0就已經被廢棄,部分APP使用webview時, 審覈被拒

14.WKWebView 中測量頁面內容高度的方式變動

iOS 13之前 document.body.scrollHeight iOS 13中 document.documentElement.scrollHeight 二者相差55 應該是瀏覽器定義高度變了

15.使用MJExtension 中處理NSNull的不一樣(必須)

這個直接會致使Crash的在將服務端數據字典轉換爲模型時,若是遇到服務端給的數據爲NSNull時, mj_JSONObject,其中 class_copyPropertyList方法獲得的屬性裏,多了一種EFSQLBinding類型的東西,並且屬性數量也不許確, 那就沒辦法了, 我只能改寫這個方法了,這個組件沒有更新的狀況下,寫了一個方法swizzling掉把當遇到 NSNull時,直接轉爲nil了。

有人問這個方法怎麼實現,其實目前咱們項目在ios13下面還沒遇到這種狀況,發一個以前項目處理null的方法,在項目裏面寫一個NSObject的分類,添加下面的方法就能夠了。你們請根據項目狀況、數據格式修改下這個方法,MJ庫裏面本身會進行替換的:

- (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property {
    //爲了解決json字符串先賦值給oc字典後,類型轉換crash問題,如:
    //json->oldValue:0
    //model中值爲NSString類型
    //若是先將json轉爲dic,dic中對應value值爲NSNumber類型,則向oldValue發送isEqualToString消息會crash
    id tempValue = oldValue;

    if ([property.type.code isEqualToString:@"NSString"]) {
        tempValue = [NSString stringWithFormat:@"%@", tempValue];

        if ([tempValue isKindOfClass:[NSNull class]] || tempValue == nil || [tempValue isEqual:[NSNull null]] ||  [tempValue isEqualToString:@"(null)"] ||  [tempValue isEqualToString:@"(\n)"] ) {
            return @"";
        }
    }
    if ([property.type.code isEqualToString:@"NSNumber"]) {
//        tempValue = [NSNumber numberWithFloat:[tempValue floatValue]];

        if ([tempValue isKindOfClass:[NSNull class]] || tempValue == nil || [tempValue isEqual:[NSNull null]] ||  [tempValue isEqualToString:@"(null)"] ||  [tempValue isEqualToString:@"(\n)"] ) {
            return @0;
        }
    }

    return tempValue;
}

  

16.StatusBar 與以前版本不一樣(必須)

以前 Status Bar 有兩種狀態,default 和 lightContent
如今 Status Bar 有三種狀態,default, darkContent 和 lightContent
如今的 darkContent 對應以前的 default,如今的 default 會根據狀況自動選擇 darkContent 和 lightContent

17.UIActivityIndicatorView(必須)

以前的 UIActivityIndicatorView 有三種 style 分別爲 whiteLarge, white 和 gray,如今所有廢棄。
增長兩種 style 分別爲 medium 和 large,指示器顏色用 color 屬性修改。

18.藍牙權限須要申請

CBCentralManager,iOS13之前,使用藍牙時能夠直接用,不會出現權限提示,iOS13後,再使用就會提示了。 在info.plist裏增長

<key>NSBluetoothAlwaysUsageDescription</key> 
<string>咱們要一直使用您的藍牙</string>

  

在iOS13中,藍牙變成了和位置,通知服務等一樣的能夠針對單個app受權的服務。

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

  

19.CNCopyCurrentNetworkInfo

iOS13 之後只有開啓了 Access WiFi Information capability,才能獲取到 SSID 和 BSSID wi-fi or wlan 相關使用變動
最近收到了蘋果的郵件,說獲取WiFi SSID的接口CNCopyCurrentNetworkInfo 再也不返回SSID的值。不仔細看還真會被嚇一跳,對物聯網的相關APP簡直是炸彈。仔細看郵件還好說明了能夠先獲取用戶位置權限才能返回SSID。
注意:目自己已經打開位置權限,則能夠直接獲取

 

20. UITabBarButton 不一樣狀態下結構不一樣,補充上述tabbar小紅點偏移
在 iOS 13 中,UITabBarButton 的控件結構會隨着其選中狀態的變化而變化,主要體現爲 UITabBarSwappableImageView 和 UITabBarButtonLabel 的位置變化。在選中時和之前同樣,是 UITabBarButton 的子控件。而在未選中狀態下放到了 UIVisualEffectView 的 _UIVisualEffectContentView 裏面。感謝@關燈俠的提醒,具體能夠看下圖的對比:

 

咱們在自定義 UITabBar 時,一般會遍歷 UITabBarButton 的子控件獲取 UITabBarSwappableImageView,好比自定義紅點時添加到這個 ImageView 的右上角,這在 iOS 13 中可能就會致使異常。

解決方案

可使用遞歸遍歷 UITabBarButton 的全部 subviews 獲取 UITabBarSwappableImageView,具體能夠參照上面 私有方法 KVC 可能致使崩潰 章節中給出的遞歸遍歷方法。

另外須要注意,未選中狀態下,添加的紅點會和 tabBar 的圖片同樣變成灰色,這一點應該也是由於其結構變化形成的。具體能夠見下圖:

 

若是想要和之前同樣未選中時也是紅色,也很簡單,把紅點添加到 UITabBarButton 上,位置再根據 UITabBarSwappableImageView 調整便可。

21. UINavigationBar 設置按鈕邊距致使崩潰


從 iOS 11 開始,UINavigationBar 使用了自動佈局,左右兩邊的按鈕到屏幕之間會有 16 或 20 的邊距。

 

 

爲了不點擊到間距的空白處沒有響應,一般作法是:定義一個 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;
        }
    }
}

  



參考連接,若有侵權,請告知,

https://github.com/ChenYilong/iOS13AdaptationTips/issues
iOS 13 適配
iOS13適配
適配 iOS13
Xcode11 和 iOS13 適配
iOS13 UI & 功能適配
解決Xcode11-beta版本新建立iOS工程低版本黑屏的問題
Modernizing Your UI for iOS13

https://www.jianshu.com/p/8183d086b931

相關文章
相關標籤/搜索