1. 程式人生 > >「 iOS知識小集 」2018 · 第 38 期

「 iOS知識小集 」2018 · 第 38 期

原文連結

更新:前兩週我們發了一條小集《Xcode 10.1 並沒有修復由於 Assets 引起的在 iOS 9 上的崩潰問題》,根據最新訊息,蘋果已經在伺服器端解決了這個問題,開發者通過 Xcode 10.1 打的 ipa 包在上傳到蘋果後臺,蘋果在處理包的過程中會自動修復。小夥伴們已親自驗證,不會在 iOS 9 上 Crash 啦~

上週公眾號釋出的以下文章:

本期知識小集的主要內容包括:

  • 研究 wkwebview 的子 view 和 的關係
  • 如何使 UIImagePickerController 支援橫屏
  • 句子拆分
  • Safe Area 的一些零散點

研究 WKWebview 的子 view 和 的關係

作者: hite和落雁

這個問題來自需求:當 webview 下拉 bounce 的時候,在漏出的部分顯示自定義的 view。類似在微信開啟一個公眾號後顯示的“此頁面由 **** 提供”,這樣的互動。

中間經過若干測試,實現此功能有三個關鍵點;

  1. 設定 webview.scrollView.backgroundColor = [UIColor clearColor]; 目的為了下拉整個頁面時,能夠漏出我們自定義 view。(這裡需要指出的是,下拉頁面出現 bounce
    效果時,漏出的 是 wkscrollview;為什麼這樣,我猜測是因為 Safari 渲染的時候,bounce 效果是出在 wkscrollview上,可參看這個測試頁面,請在 Safari 裡開啟)
  2. 結合 1,將這個自定義 view,放在 WKWebviewWKScrollView 之間(猜測,webview.scrollViewWKScrollView 的代理物件,而 WKScrollView 是 的代理元素,是否真的這樣需要看看原始碼)。
  3. 新增自定義 view 到 WKScrollView 裡的時機是 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    , 而不是 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation 因為不同頁面書寫方式,導致有些樣式會生效時機不同,頁面載入完畢並不是個很好的時機。

在生成 webview 的時候,設定 webview.scrollView.backgroundColor = [UIColor clearColor];特別的需要說明下,當 h5 在 body 上寫內聯樣式 <body style="background-color:red">; 或者寫 style 樣式;或者外聯 <link rel="stylesheet" href> 三種寫法,去設定 body 的顏色,是否生效看不同的情況;

  1. 當設定的 body 顏色是 #ffffff 白色時,不論什麼時候去設定 body 顏色都不會覆蓋 webview.scrollView.backgroundColor 的顏色。
  2. 當設定的顏色是非白色時,會覆蓋 webview.scrollView.backgroundColor

通過對照 HTML 的 DOM 層級和 WKWebview 的層級,

有以下發現;

  1. html 裡下拉時, bounce 效果後面的背景元素是 WKScrollView,所以設定 body 顏色會設定到 WKScrollView 的背景色。
  2. html 裡其他元素全部由 WKContentView 巢狀。當整個頁面是長頁面需要分頁時,會分多個 WKCompositingView 逐個顯示;

使用上述方案實現下拉時顯示自定義元素有個問題;

  1. 在開始滑動 scrollView 時候,設定 webview.scrollView.backgroundColor 的顏色,會將 h5 自己設定的背景色覆蓋,所以 h5 要儘量不要依賴 body 的背景色做滑動背景;
  2. 某些頁面,如測試頁面2, 頭部有個 fixed 元素,下拉時也會漏出 bounce 背景色。此時如果背景色設定透明後出現一個很奇怪的 漏出,這時候不應該漏出。如果解決這個問題呢,如果真的要解決這個問題,可能需要去讀 html 的樣式,這樣就比較麻煩了。
  3. 對問題 2 ,有個討巧的方案就是將漏出的自定義元素放在 fixed 元素的後面,如微信那樣。具體樣式可以將 測試頁面2 放到微信裡看效果。

如果真正要解決問題 2 ,目前還需要再找找方案,希望看到 webkit2 的原始碼後能有方案。

如何使 UIImagePickerController 支援橫屏

作者: halohily

很多同學在開發橫屏應用時,使用系統的 UIImagePickerController 會發現它預設只支援豎屏。筆者也遇到了這個問題,經過一番探究,如下的方式效果是最佳的:

首先,在 present 這裡的 UIImagePickerController 物件 picker 之前,設定 picker 的 modalPresentationStyleUIModalPresentationOverCurrentContext,這時執行會發現橫屏時它也可以正常彈出了,只是旋轉裝置時它不能跟隨裝置方向正常轉動。

接下來,為 UIImagePickerController 新增一個 category,重寫 shouldAutorotate 方法返回 true,重寫 supportedInterfaceOrientations 方法返回 UIInterfaceOrientationMaskAll。這時再執行會發現不僅可以橫屏彈出,也可以正常旋轉了。

句子拆分

作者: Lefe_x

把下面這段話拆分成句子,你會用什麼方案呢?

知識小集是由幾位志同道合的夥伴組成。你瞭解這個團隊嗎?我們在一起相處了 1 年多的時光!我想說:“我們是最棒的!”
複製程式碼

我想到的方案有:正則表示式;使用 NSScanner ;使用 componentsSeparatedByCharactersInSet: ;但這幾種方案都比較麻煩,後來不經意間發現了下面這個方法。

程式碼如下:

NSString *text = @"知識小集是由幾位志同道合的夥伴組成。你瞭解這個團隊嗎?我們在一起相處了 1 年多的時光!我想說:“我們是最棒的!”";
[text enumerateSubstringsInRange:NSMakeRange(0, [text length]) options:NSStringEnumerationBySentences usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
    NSLog(@"sentence: %@ range: %@", substring, NSStringFromRange(substringRange));
}];
複製程式碼

執行結果如下:

sentence: 知識小集是由幾位志同道合的夥伴組成。 range: {0, 18}
sentence: 你瞭解這個團隊嗎? range: {18, 9}
sentence: 我們在一起相處了 1 年多的時光! range: {27, 17}
sentence: 我想說:“我們是最棒的!” range: {44, 13}
複製程式碼

Safe Area 的一些零散點

作者: 這個湯圓沒有餡weibo.com/u/660346950…

先看圖一尺寸圖。

我們都知道,iOS 11 引入了 Safe Area 這個概念。在 xib 或者 storyboard 上新增 subview,都是會新增在 Safe Area 上的。例如:在 vc 上新增一個 view,上下左右約束分別為 0,在 iPhone X 和 iPhone 6 上展示不一樣,如下圖。純程式碼建立的時候不會出現這個問題,因為 subview 是直接新增在 self.view 上面。

很明顯,在 iPhone X 上底下會有一個 34pt 高度的留白區。分別列印一下兩個機型的 self.view.safeAreaInsets,如下圖。

那麼假使現在,我希望在 iPhone X 機型上,底下不要留白。頁面展示效果跟 iPhone 6 一樣。然而 safeAreaInsets 是隻讀屬性,無法通過修改值達到目的。

第一種方法,Align Bottom to:Safe Area 的值改為-34。但是如果後期出了新的機型,那麼這個值就不再適配,因為不推薦。

第二種方法,在 bottom 的約束上,直接以superView為參照,如下圖。

另外補充幾點:

  • - additionalSafeAreaInsets:controller 可以擴充套件安全區域,如果我們設定 self.additionalSafeAreaInsets = UIEdgeInsetsMake(20, 0, 0, 20); 意思就是在原有的 safeAreaInsets 值中增加對應的邊距值。如果原來的是 {10, 0, 0, 10} , 則最後得出的邊距是 {30, 0, 0, 30}。
  • - (void)viewSafeAreaInsetsDidChange: 當檢視的安全區域發生變更時會觸發該方法,可以通過該方法來處理安全區域變更時的UI佈局。
  • - insetsLayoutMarginsFromSafeArea: 預設值是YES,如果設定為 NO,所有的檢視佈局將會忽略 safeAreaInsets 這個屬性了。這個只對純程式碼佈局檢視有效,如果是 xib 或者 storyboard 佈局的話不起作用。一般用於 tableView 居多。

關注我們

歡迎關注我們的公眾號:iOS-Tips,也歡迎加入我們的群組討論問題。可以公眾號留言 iosflutter 等關鍵詞獲取入群方式。