前天9月21日,手機更新到iOS 11, 看了一下早期上架 App Store 的應用, 啥問題都沒有, 心里正沾沾自喜也松了一口氣......
可昨夜更新到 Xcode9后編譯代碼,發現還有一些問題的, 因為同時管理了好幾個應用,其他應用也是需要同步作 iOS 11適配, 所以好記不如賴筆頭, 省得適配其他應用的時候忘記.....
問題 1: UINavigationBar 內UIBarButtonItem按鈕錯位拉伸
問題描述:
好在公司的幾個應用的導航欄設計并不復雜, 不需要自定義 titleView,所以不涉及到自定義導航titleView的寬度適配問題.
但是,自定義的 MANavigationController里所重寫的UIBarButtonItem返回按鈕 icon 被拉寬,并且各界面導航欄UIBarButtonItem按鈕, 也同樣擠壓和錯位,設置的 title 也看不到了.
以下2張截圖就是Xcode9編譯代碼發現的iOS 11下UIBarButtonItem按鈕出現的問題:
-
圖1: 主界面頂部左右3個按鈕被拉伸
[圖片加載中,請耐心等待....]
IMG_4897.PNG 圖2: 頂部導航欄中間的 title 消失, 3個按鈕錯位和被拉伸
[圖片加載中,請耐心等待....]
解決方案:
最簡單的解決方案: 將 UIbutton 包裝到 UIview 內, 再通過initWithCustomView方法傳遞給UIBarButtonItem
//針對 iOS11適配改寫 的關鍵性代碼, 就這么幾行,完全搞定了
UIView *containVew = [[UIView alloc] initWithFrame:btn.bounds];
[containVew addSubview:btn];
return [[UIBarButtonItem alloc]initWithCustomView:containVew];
以下代碼摘自 MISSAJJ 寫的MAButtonTool工具類,為了節約時間,提高創建按鈕控件的效率,特抽出一個創建各種按鈕的類方法
支持:
1,圖片按鈕 (默認居中按鈕,左返回按鈕,右分享按鈕)
2,自定義文字圖片靠左靠右按鈕
3,按項目需求,設定了按鈕樣式和位置樣式
4,只要修改一下分享和返回按鈕圖片就可以直接應用到項目中了
5,由于美工給的圖片素材尺寸會不同,所以按鈕的frame和setImageEdgeInsets可根據項目素材情況在VC層創建后重寫調整
6,支持block調用按鈕事件
使用方法請看:https://github.com/MISSAJJ/MAButtonTool
^_^ 我只要在這個工具類里針對 iOS 11增加幾行包裝代碼,
就解決了全部項目在 iOS 11下導航欄按鈕錯位問題,
這就是包裝工具類的好處......
#pragma mark ==[自定義 block 導航欄 按鈕]==
+(UIBarButtonItem *)createButtonWithImage:(NSString * __nullable)imageStr position:(MAButtonToolPostion)position type:(MAButtonToolType)type actionBlock:(ButtonItemBlock)block
{
UIButton* btn;
if (position == MAButtonToolPostionLeft) { //位置靠左
if (type ==MAButtonToolTypeBack) { //返回按鈕
btn = [self createLeftBackButton];
}else{
btn = [self createLeftButton:imageStr]; //默認靠左按鈕
}
}else if (position == MAButtonToolPostionRight) { //位置靠右
if (type ==MAButtonToolTypeShare) { //分享按鈕
btn = [self createRightShareButton];
}else{
btn = [self createRightButton:imageStr];//默認考右按鈕
}
}else { //位置中間
btn = [self createButton:imageStr];
}
[btn addTouchAction:^(UIButton *btn) {
if (block)
{
block(btn);
}
}];
//針對 iOS11適配改寫
UIView *containVew = [[UIView alloc] initWithFrame:btn.bounds];
[containVew addSubview:btn];
return [[UIBarButtonItem alloc]initWithCustomView:containVew];
}
#pragma mark ==[左自定義圖片按鈕]==
+ (UIButton *)createLeftButton:(NSString *)imageStr
{
UIButton* btn= [self createButton:imageStr];
[btn setImageEdgeInsets:UIEdgeInsetsMake(0, -10, 0, 10)];
return btn;
}
#pragma mark ==[右自定義圖片按鈕]==
+ (UIButton*)createRightButton:(NSString*)imageStr
{
UIButton* btn=[self createButton:imageStr];
[btn setImageEdgeInsets:UIEdgeInsetsMake(0, 10, 0, -10)];
return btn;
}
#pragma mark ==[左返回按鈕]==
+ (UIButton*)createLeftBackButton
{
UIButton* btn= [self createButton:@"backarrow_white"];
btn.frame = CGRectMake(0, 0, 50, 50);
[btn setImageEdgeInsets:UIEdgeInsetsMake(0, -20, 0, 20)];
return btn;
}
#pragma mark ==[右分享按鈕]==
+ (UIButton*)createRightShareButton
{
UIButton* btn= [self createButton:@"share_white"];
btn.frame = CGRectMake(0, 0, 35, 35);
[btn setImageEdgeInsets:UIEdgeInsetsMake(0, 10, 0, -10)];
return btn;
}
解決問題后的導航欄顯示截圖
-
圖1: 導航欄左右3個按鈕顯示正常, 中間的標題也顯示正常了
[圖片加載中,請耐心等待....]
IMG_4901.PNG -
圖2: 主界面頂部左右3個按鈕顯示正常了
[圖片加載中,請耐心等待....]
IMG_4901.PNG
問題 2 : Xcode9下相冊等訪問權限問題
查了資料說iOS11下,蘋果對相冊的權限key做了調整,原來的 NSPhotoLibraryUsageDescription ,在iOS11之后,改成了NSPhotoLibraryAddUsageDescription。
針對于此測試了一下應用,果然毫無懸念, 立即去 info.plist 把 key 改成NSPhotoLibraryAddUsageDescription, 很快解決問題了.
圖3: info.plist內設置NSPhotoLibraryAddUsageDescription權限
[圖片加載中,請耐心等待....]
問題 3 : 等我好好睡個美容覺之后, 再繼續寫吧....... : )
昨夜熬到凌晨3點,適配發布好了[AR 掃描器]APP應用,已經提交審核,
今夜適配另外一個[樂游博物館]APP 應用, 不知不覺又已經凌晨1:00了,
這兩個星期幾乎每天都只睡了幾個小時,
好怕自己迅速變老,
好怕自己腎衰竭猝死,
好怕自己吃東西沒滋味,
好怕自己神經衰落睡不著,
今天可是周末啊! ~周末啊! ~周末啊! ~
.........哎........
問題 4 : MJRefresh下拉刷新適配 iOS 11和 iPhone X問題
熬夜完成了公司的2個應用的 iOS 11適配之后, 今晚開始適配自己的一些項目,打開其中一個項目在不同的模擬器下分別編譯看效果, 底部自定義 tabbar 顯示沒有問題, 但頂部是隱藏了 NavigationBar并采用了MJRefresh下拉刷新,發現有錯位..
圖4: iOS 11下拉刷新出現錯位問題
[圖片加載中,請耐心等待....]
圖4: iPhone X下拉刷新出現錯位問題
[圖片加載中,請耐心等待....]
我的解決方案: (灰常簡單)
因為我的布局是 CollectionView, 所以只要設置 iOS 11的新特性方法contentInsetAdjustmentBehavior為UIScrollViewContentInsetAdjustmentNever就可以了
以此類推,如果是 UITableView 布局的,也是設置contentInsetAdjustmentBehavior
判定 iOS 11的方法, 官方建議的方法:
以下是官方的屏幕尺寸, 原本最初的想法就是根據屏幕的高度812pt來判定
官方建議的方法 :
if (@available(iOS 11.0, *)) {
}else{
}
我的適配代碼:
if (@available(iOS 11.0, *)) {
_collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
// Fallback on earlier versions
}
判定iPhoneX的方法 :
#define isIPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? [[UIScreen mainScreen] currentMode].size.height==2436 : NO)
其他的一些相關適配方法:(摘自 MJRefresh討論區的解決方案)
注:首先這個下拉刷新的偏移量并不是MJRefresh造成的,但是確實需要適配,比如通欄ViewController顯示的時候,劉海會遮住下拉刷新的組件,解決辦法是對下拉刷新控件自定義,調整內部組件的布局,通欄的ViewController地方使用自定義的下拉控件。
對于iOS11下的iPhoneX適配下拉刷新有以下幾點:
1,首先請配置相應的啟動圖,尺寸是1125*2436;
2,對于通欄ViewController中的UIScrollView,系統會默認根據contentInsetAdjustmentBehavior屬性改變其bounds的y值為-44,導致UIScrollView中的所有子控件下移,解決辦法是,對于通欄ViewController,請設置其UIScrollView的contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever。
其他適配點:
1,iOS11下的iPhoneX的導航欄為高度44,狀態欄高度也調整為44,所以整個頂部狀態欄的高度和導航欄的高度一起是88,自定義導航欄的同學需要根據系統機型控制導航欄高度;
2,iOS11下的iPhoneX的tabBar的高度調整為83,自定義tabBar的同學建議使用Frame布局;
3,iOS11下的iPhoneX下,屏幕底部默認顯示了長條狀的Home鍵指示器,可以通過UIViewController (UIHomeIndicatorAutoHidden)分類中的prefersHomeIndicatorAutoHidden來隱藏,但是官方并不建議這樣做。
適配 iOS 11和 iPhone X 之后的界面效果
我的建議:
在 iPhone X 下還是最好還是有導航欄的設計比較美觀, 因為隱藏導航欄后, 劉海會把頂部控件切割掉, 畫面就比較尷尬了....哈哈~~
圖5: 適配后的截圖
[圖片加載中,請耐心等待....]
圖6: 適配后的下拉刷新,同時隱藏導航欄的截圖
圖7: 界面上滑顯示導航欄的效果
iPhone X 導航欄錯位問題
iOS11下的iPhoneX的導航欄為高度44,狀態欄高度也調整為44,所以整個頂部狀態欄的高度和導航欄的高度一起是88,所以在自定義導航欄里針對 iPhone X 修改的高度
我的解決方法:
我所有的項目都是使用了宏定義參數的方法來設置各種控件的, 所以只要改寫這些相關宏定義參數, 整個項目都同步做好了適配, 所以平時的積累和歸納思維很重要,關鍵時刻可以減輕很多不必要的重復工作量.
/*****宏定義 *****/
//導航欄高度
#define MANavBarHeight isIPhoneX ? 88 : 64
//底部Tabbar 高度
#define MATabBarHeight isIPhoneX ? 83 : 49
//狀態欄高度
#define MAStatusBarHeight isIPhoneX ? 44 : 20
//一些相關同步對應的代碼
// set navigationBar backgroundImage
- (void)MA_setBackgroundImage:(UIImage *)image
{
[self.backgroundView removeFromSuperview];
self.backgroundView = nil;
if (self.backgroundImageView == nil)
{
// add a image(nil color) to _UIBarBackground make it clear
[self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
self.backgroundImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), MANavBarHeight)];
self.backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
// _UIBarBackground is first subView for navigationBar
[self.subviews.firstObject insertSubview:self.backgroundImageView atIndex:0];
}
self.backgroundImageView.image = image;
}
// set navigationBar barTintColor
- (void)MA_setBackgroundColor:(UIColor *)color
{
[self.backgroundImageView removeFromSuperview];
self.backgroundImageView = nil;
if (self.backgroundView == nil)
{
// add a image(nil color) to _UIBarBackground make it clear
[self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
self.backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), MANavBarHeight)];
self.backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
// _UIBarBackground is first subView for navigationBar
[self.subviews.firstObject insertSubview:self.backgroundView atIndex:0];
}
self.backgroundView.backgroundColor = color;
}
其他方法:
網絡里也有相關這種重寫layoutSubviews的方法,我試過之后發現導航欄變透明,并且顏色怪怪的了, 所以最終還是用了上面的方法解決了問題, 下面的這種方法大家也可是嘗試一下
自定義的navigationBar,在iOS11上運行就可能出現布局錯亂的bug,
解決辦法是重寫UINavigationBar的layoutSubviews方法調整布局:
- (void)layoutSubviews {
[super layoutSubviews];
//注意導航欄及狀態欄高度適配
self.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), MANavBarHeight);
for (UIView *view in self.subviews) {
if([NSStringFromClass([view class]) containsString:@"Background"]) {
view.frame = self.bounds;
}
else if ([NSStringFromClass([view class]) containsString:@"ContentView"]) {
CGRect frame = view.frame;
frame.origin.y = statusBarHeight;
frame.size.height = self.bounds.size.height - frame.origin.y;
view.frame = frame;
}
}
}
適配 iPhone X 之后的截圖
問題 5 : XCode9打包上傳遇到的問題和解決方式
問題:上傳后返回警告,缺失1024px的圖標
原因和解決: 升級Xcode9后Assets/AppIcon下多了一個1024pt的icon框,需要補上缺失的圖標
問題 6 : iPhone X下自定義鍵盤的高度如何增加34px 的高度
iPhone X 的默認系統鍵盤 : 底部會自動加上高度
問題: 自定義的表情鍵盤的底部在 iPhone X 下沒有增加高度
將自定義表情emojiToolBarView設置為 UITextView輸入框的inputAccessoryView,emojiToolBarView會置頂于系統鍵盤,并且跟隨系統鍵盤向上向下移動
self.customTextView.inputAccessoryView = self.emojiToolBarView;
//點擊自定義表情按鈕事件的邏輯
- (IBAction)emotionBtnClicked:(id)sender {
UIButton *button = sender;
if (!isEmotionShow) {
[button setImage:[UIImage imageNamed:@"board_system"] forState:UIControlStateNormal];
isEmotionShow = YES;
isKeyboard = NO;
// self.customEmojiBoardView為自定義表情鍵盤 View
self.customTextView.inputView = self.customEmojiBoardView;
[self.customTextView resignFirstResponder];
}else{
[button setImage:[UIImage imageNamed:@"board_emoji"] forState:UIControlStateNormal];
isEmotionShow = NO;
isKeyboard = YES;
self.customTextView.inputView = nil;
[self.customTextView resignFirstResponder];
}
}
解決辦法: 將你自定義的鍵盤的customEmojiBoardView 的高度加上34就可以了
//自定義表情鍵盤的寬高
CGFloat viewWidth = [UIScreen mainScreen].bounds.size.width - 16;
//原本自定義的高度是 216, 那就判定 iPhone X 下高度 再加上 34 為: 216+34 ;
CGFloat viewHeight = isPhoneX ? 250 : 216;
//自定義表情鍵盤customEmojiBoardView 的初始化
- (instancetype)init {
self = [super initWithFrame:CGRectMake(0, 0,viewWidth, viewHeight)];
if (self) {
以下代碼省略......
}
return self;
}
最后:
Contact 聯系方式:
希望能有更多的獅子一起共勉探討學習,愉快奔跑!
聯系方式: QQ 996174446 [驗證:iOS 攻城獅]
MISSAJJ網站 : http://www.MISSAJJ.com
Github : https://github.com/MISSAJJ
GitBook : https://www.gitbook.com/@missajj
MISSAJJ琴瑟靜聽( Swift 和 Objective-C )iOS 開發項目電子書
https://github.com/MISSAJJ/MISSAJJ_IOS_DEVELOPMENT_BOOK