自從6月份的 WWDC大會(huì)展示了
iOS 13
的新版本之后溃睹,廣大開發(fā)者朋友又面臨著新一輪的系統(tǒng)升級適配工作;隨著蘋果9月份發(fā)布會(huì)腳步的臨近锌俱,對公司的App升級適配勢在必行。
iOS 13發(fā)現(xiàn)問題回顧
- 禁止用戶獲取或直接設(shè)置私有屬性:調(diào)用
setValue:forKeyPath:
负蚊、valueForKey:
方法會(huì)引起App崩潰。例如:UITextField
修改_placeholderLabel.textColor
颓哮、UISearchBar
修改_searchField
-
UITextField
的leftView
和rightView
調(diào)整:部分視圖位置顯示異常 -
UITabBar
部分調(diào)整:UITabBarItem
播放gif顯示比例有問題家妆;UITabBarItem
只顯示圖片時(shí),圖片位置偏移冕茅;Badge
文字顯示偏大 -
UITableView
的cell
選中樣式失效 - 第三方SDK的閃退兼容問題
將所有問題歸納總結(jié)伤极,得出以下幾點(diǎn)解決方案的建議和示例代碼,記錄一下
1. UITextField
-
設(shè)置
placeholder
引起的閃退在
iOS 13
之前姨伤,設(shè)置placeholder
有三種方案:-
基于
KVO
簡單粗暴的修改私有屬性(iOS 13
禁用)[textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"]; [textField setValue:[UIFont boldSystemFontOfSize:16] forKeyPath:@"_placeholderLabel.font"];
-
設(shè)置
attributedPlaceholder
屬性textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"placeholder" attributes:@{NSForegroundColorAttributeName: [UIColor darkGrayColor], NSFontAttributeName: [UIFont systemFontOfSize:13]}];
-
重寫
UITextField
子類的drawPlaceholderInRect:
方法- (void)drawPlaceholderInRect:(CGRect)rect { [self.placeholder drawInRect:rect withAttributes:@{NSForegroundColorAttributeName: [UIColor purpleColor], NSFontAttributeName: [UIFont systemFontOfSize:13]}]; }
適配
iOS 13
時(shí)哨坪,可根據(jù)實(shí)際情況選取后兩種方案解決閃退問題。如果項(xiàng)目中重復(fù)使用了同一種UITextField
的樣式乍楚,推薦使用第三種方案当编,創(chuàng)建UITextField
的子類。修改建議: 采用第二種方案徒溪,創(chuàng)建
UITextField
的Category
文件忿偷,里面封裝好修改placeholder
的方法,后續(xù)修改都可統(tǒng)一直接調(diào)用這些方法// UITextField+CIPlaceholder.m文件 #import "UITextField+CIPlaceholder.h" @implementation UITextField (CIPlaceholder) - (void)setPlaceholderFont:(UIFont *)font { [self setPlaceholderColor:nil font:font]; } - (void)setPlaceholderColor:(UIColor *)color { [self setPlaceholderColor:color font:nil]; } - (void)setPlaceholderColor:(nullable UIColor *)color font:(nullable UIFont *)font { if ([self checkPlaceholderEmpty]) { return; } NSMutableAttributedString *placeholderAttriString = [[NSMutableAttributedString alloc] initWithString:self.placeholder]; if (color) { [placeholderAttriString addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(0, self.placeholder.length)]; } if (font) { [placeholderAttriString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, self.placeholder.length)]; } [self setAttributedPlaceholder:placeholderAttriString]; } - (BOOL)checkPlaceholderEmpty { return IsStrEmpty(self.placeholder); } @end
-
-
子視圖
leftView
和rightView
顯示異常修改建議:將需要顯示的視圖包裝在一個(gè)簡單的
UIView
中或者在需要顯示的自定義視圖子類里词渤,實(shí)現(xiàn)systemLayoutSizeFittingSize:
方法// 示例代碼 - (void)buildTextField { UITextField *textField; // iOS 13之前 textField.rightView = [self buildButtonForRightView]; // iOS 13之后 textField.rightView = [self buildTextFieldRightView]; } // iOS 13之前正常 - (UIButton *)buildButtonForRightView { UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // do somethings return button; }
-
將顯示的視圖包裝在一個(gè)簡單的
UIView
中// iOS 13之后需要封裝一層 - (UIView *)buildTextFieldRightView { UIButton *button = [self buildButtonForRightView]; // 封裝一層 UIView *rightView = [[UIView alloc] initWithFrame:button.bounds]; [rightView addSubview:button]; return rightView; }
-
在需要顯示的自定義視圖子類里牵舱,實(shí)現(xiàn)
systemLayoutSizeFittingSize:
方法// CICustomButton.m文件 #import "CICustomButton.h" @implementation CICustomButton // iOS 13之后需要實(shí)現(xiàn)該方法 - (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize { return CGSizeMake(100, 30); } @end ------------------------ // Build TextFiled頁面 // iOS 13之后串绩,修改UIButton為CICustomButton - (UIButton *)buildButtonForRightView { UIButton *button = [CICustomButton buttonWithType:UIButtonTypeRoundedRect]; // do somethings return button; }
-
2. UISearchBar
通過valueForKey
缺虐、setValue: forKeyPath
獲取和設(shè)置私有屬性程序崩潰
// 修改searchBar的textField
UISearchBar *searchBar = [[UISearchBar alloc] init];
// iOS 13之前可直接獲取,然后修改textField相關(guān)屬性
UITextField *searchTextField = [searchBar valueForKey:@"_searchField"];
修改建議:可遍歷searchBar
的所有子視圖礁凡,找到指定的UITextField
類型的子視圖高氮,根據(jù)上述UITextField
的相關(guān)方法修改屬性;也可根據(jù)UITextField
自定義UISearchBar
的顯示
// UISearchBar+CIChangePrivateSubviews.m文件
// 修改SearchBar的系統(tǒng)私有子視圖
#import "UISearchBar+CIChangePrivateSubviews.h"
@implementation UISearchBar (CIChangePrivateSubviews)
/// 修改SearchBar系統(tǒng)自帶的TextField
- (void)changeSearchTextFieldWithCompletionBlock:(void(^)(UITextField *textField))completionBlock {
if (!completionBlock) {
return;
}
UITextField *textField = [self findTextFieldWithView:self];
if (textField) {
completionBlock(textField);
}
}
/// 遞歸遍歷UISearchBar的子視圖顷牌,找到UITextField
- (UITextField *)findTextFieldWithView:(UIView *)view {
for (UIView *subview in view.subviews) {
if ([subview isKindOfClass:[UITextField class]]) {
return (UITextField *)subview;
}else if (!IsArrEmpty(subview.subviews)) {
return [self findTextFieldWithView:subview];
}
}
return nil;
}
@end
3. UITableView
iOS 13
設(shè)置cell.contentView.backgroundColor
會(huì)影響cell
的selected
或者highlighted
時(shí)的效果
例如:如果設(shè)置cell.selectedBackgroundView
為自定義選中背景視圖剪芍,并修改cell.contentView.backgroundColor
為某種不透明顏色;contentView
就會(huì)遮蓋cell.selectedBackgroundView
窟蓝,最終導(dǎo)致無法看到自定義的selectedBackgroundView
效果罪裹。
修改建議:不設(shè)置contentView.backgroundColor
時(shí),默認(rèn)值為nil
运挫;改為直接設(shè)置cell
本身背景色
// 自定義cell.m文件
// iOS 13之前正常
self.contentView.backgroundColor = [UIColor blueColor];
// iOS 13改為
self.backgroundColor = [UIColor blueColor];
備注:iOS 13
對UITableView
還做了一些其他的修改状共,詳細(xì)內(nèi)容可查閱最底部 參考內(nèi)容1,整個(gè)網(wǎng)頁搜索UITableViewCell
即可
4. UITabbar
-
Badge
文字顯示不正常Badge
默認(rèn)字體大小谁帕,iOS 13
從之前13號字體變?yōu)?7號字體修改建議:在初始化TabBarController時(shí)峡继,在需要顯示
Badge
的ViewController
處調(diào)用setBadgeTextAttributes:forState:
方法// iOS 13需要添加 if (@available(iOS 13, *)) { [viewController.tabBarItem setBadgeTextAttributes:@{NSFontAttributeName: CI_FONT_13} forState:UIControlStateNormal]; [viewController.tabBarItem setBadgeTextAttributes:@{NSFontAttributeName: CI_FONT_13} forState:UIControlStateSelected]; }
-
字體顏色異常
iOS 13
不設(shè)置self.tabBar.barTintColor = [UIColor clearColor];
時(shí)字體顏色會(huì)顯示藍(lán)色,iOS 13
之前設(shè)置與否無影響修改建議:設(shè)置
tabBar.barTintColor
顏色為UIColor clearColor]
// 自定義TabBarController.m文件 - (void)viewDidLoad { [super viewDidLoad]; self.tabBar.barTintColor = [UIColor clearColor]; // 整個(gè)項(xiàng)目只有一種TabBarController時(shí)或者多個(gè)相同風(fēng)格時(shí)可設(shè)置全局風(fēng)格(其他情況不推薦) // [[UITabBar appearance] setBarTintColor:[UIColor clearColor]]; }
5. UITabBarItem
-
播放gif匈挖,設(shè)置
ImageView
圖片時(shí)注意設(shè)置圖片的scale
比例// 根據(jù)路徑取gif數(shù)據(jù) NSData *data = [NSData dataWithContentsOfFile:path]; CGImageSourceRef gifSource = CGImageSourceCreateWithData(CFBridgingRetain(data), nil); size_t gifCount = CGImageSourceGetCount(gifSource); CGImageRef imageRef = CGImageSourceCreateImageAtIndex(gifSource, i,NULL); // iOS 13之前 UIImage *image = [UIImage imageWithCGImage:imageRef] // iOS 13需要注意:添加scale比例(該imageView將展示該動(dòng)圖效果) UIImage *image = [UIImage imageWithCGImage:imageRef scale:image.size.width / CGRectGetWidth(imageView.frame) orientation:UIImageOrientationUp]; CGImageRelease(imageRef);
-
播放gif碾牌,需找到設(shè)置的
ImageView
視圖// UITabBarItem+CIChangePrivateSubviews.m文件 // 修改TabbarItem系統(tǒng)私有子視圖 #import "UITabBarItem+CIChangePrivateSubviews.h" @implementation UITabBarItem (CIChangePrivateSubviews) /// 修改UITabBarSwappableImageView - (void)changeSwappableImageViewWithCompletionBlock:(void(^)(UIImageView *imageView))completionBlock { if (!completionBlock) { return; } UIView *tabBarButton = [self valueForKey:@"view"]; for (UIView *subviews in tabBarButton.subviews) { if ([NSStringFromClass([subviews class]) isEqualToString:@"UITabBarSwappableImageView"]) { completionBlock((UIImageView *)subviews); } } }
-
只顯示圖片康愤,沒有文字時(shí)圖片的位置調(diào)整
iOS 13
不需要調(diào)整imageInsets
,圖片會(huì)自動(dòng)居中顯示舶吗,如果設(shè)置會(huì)造成圖片位置有些許偏移修改建議:添加版本限制條件征冷,只在
iOS 13
之前調(diào)用設(shè)置方法if (IOS_VERSION < 13.0) { viewController.tabBarItem.imageInsets = UIEdgeInsetsMake(5, 0, -5, 0); }
6. 彈出ViewController樣式變化
模態(tài)展示UIModalPresentationStyle
類型新增UIModalPresentationAutomatic API_AVAILABLE(ios(13.0)) = -2
用戶調(diào)用presentViewController:animated:completion:
方法彈出視圖時(shí),iOS 13
效果變化更炫酷誓琼,可以在iOS 13
系統(tǒng)App中體驗(yàn)到這種變化资盅;
如果不希望使用這種效果,可利用Runtime
方法踊赠,恢復(fù)設(shè)置modalPresentationStyle
為UIModalPresentationFullScreen
// UIViewController+CIChangePresentStyle.m文件
#import "UIViewController+CIChangePresentStyle.h"
@implementation UIViewController (CIChangePresentStyle)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
//替換方法
SEL originalSelector = @selector(presentViewController:animated:completion:);
SEL swizzledSelector = @selector(ci_presentViewController:animated:completion:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);;
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
- (void)ci_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
viewControllerToPresent.modalPresentationStyle = UIModalPresentationFullScreen;
[self ci_presentViewController:viewControllerToPresent animated:flag completion:completion];
}
@end
7. 第三方SDK相關(guān)
-
友盟社會(huì)化分享SDK:使用“新浪微博完整版”閃退
替換新浪微博最新的SDK版本Github地址呵扛,友盟集成SDK暫時(shí)未更新
-
高德地圖相關(guān)等其他第三方SDK更新
查看相關(guān)Github或者官方SDK下載地址,更新最新的SDK即可
以上就是適配iOS 13
的一些修改建議筐带。如果各位朋友發(fā)現(xiàn)有一些新問題和解決方案今穿,可以在評論區(qū)留言,希望大家暢所欲言伦籍,共同發(fā)現(xiàn)并幫助解決問題蓝晒。