【譯】UIVisualEffectView教程

前言

最近感受本身老是學習網絡相關的, 有點"疲勞"了. 因此今天換個口味, 試着翻譯下國外大神的博客. 有很差的地方還請賜教!ios

原文連接: www.raywenderlich.com/178486/uivi…算法

正文

從iOS7開始, 系統風格有了使人激動的改變, 模糊效果在APP設計中扮演了重要的角色. 若你使用適當, 模糊效果能夠顯著的提升APP的視覺感覺.

先讓咱們一塊兒看看蘋果是如何在系統中使用的. 數據庫

其中, 控制中心是一個值得關注的示例. 模糊背景爲控制中心的操做提供環境 - 雖然控制中心不屬於某一個APP, 但它卻顯示在這些活動APP的上方.swift

通知中心也使用了該效果, 可是, 這裏不是讓整個背景都模糊了, 每個extension或通知都有本身模糊的背景. 這不只看上去漂亮, 並且使每個元素都很顯眼.xcode

那麼如何在本身的APP中再現這些效果呢? 沒錯, 就是使用iOS內建的UIVisualEffectView! 該篇, 你將學到關於使用"模糊效果"的一切, 以使你的APP更出衆.bash

關於"模糊效果"你須要瞭解的事實

如何優雅,高效的使用須要必定的技巧. 這裏會瞭解到"模糊效果"使用到的常規算法.網絡

模糊效果是如何工做的

全部的模糊效果都始於一張圖片. 爲了實現該效果, 你須要對圖片的每個像素應用模糊算法(blurring algorithm), 這樣能夠獲得一個均勻的帶有模糊效果的副本. 不一樣種類的模糊算法有很大差別, 而且錯綜複雜, 這裏咱們僅僅討論一個經常使用的Gaussian blur(高斯模糊).app

一般, 模糊算法會根據一個像素周圍的像素爲其生成一個新的色值.考慮下面的網格圖片:ide

上面的每個網格單元表明了一個獨立的像素, 每個像素都有一個1~10之間的數字. 當模糊算法在計算中間像素對應的新值時, 會取其周圍數字的平均值填入其中. 獲得下面的結果:佈局

你能夠對原始圖片的每個像素都執行上述過程. 上述過程只是對某一個像素周圍的每一個方向取一個像素計算新的值. 你能夠擴大模糊半徑(上述案例的中間像素的外圍像素個數)從而增長模糊程度. 下面是個例子:

注意事項: 一般, 更大的模糊半徑意味着處理圖片須要更多的資源. iOS一般會將處理圖片的任務轉交給GPU, 去保證主線程的通暢.

模糊效果設計策略

人們更傾向於把注意力集中在清晰的元素上, 而不是不清晰的. 無論你信仍是不信, 這就是咱們的眼睛工做的結果. 隨着物體變近或遠, 眼睛隨之聚焦, 這就是適應(Focusing on an object as it moves closer or further away from the eye is known as accommodation), 是他幫助你觀察周圍事物的深度和距離.

APP的設計師們運用了這個事實, 將屏幕上那些不重要的元素變得模糊, 從而令人們的實現保留在清晰的元素上.下面是一個示例, Twitter客戶端的截屏:

上面的圖片中, 背後的用戶界面幾乎是不能辨別的, 這爲用戶提供了一個環境, 去識別他們處在哪一個層級關係中.例如, 你可能會意識到, 一旦你選擇了列出帳號中的一個, 你就會返回到後面帶有模糊效果的視圖中.

注意: 避免在你的APP中濫用模糊效果.即便模糊能提供很好看的效果, 若是你使用不當或使用過於頻繁, 它也會使人煩惱.

跟隨設計標準去使用模糊能夠直接吸引用戶注意力, 那樣你幾乎不會失敗.查看Apple開發者中心的iOS Human Interface Guidelines document文檔中Designing for iOS部分能夠獲取更多信息.

開始動手

爲了學習如何實現模糊效果, 你須要在GrimmAPP中添加一些.

這個APP向用戶展現了不少童話故事. 當用戶點擊其中一個時, APP會在屏幕上展示整個故事.用戶能夠自定義展示的字體, 文本的對其方式, 或顏色主題(白天或夜晚).

你能夠下載這個工程開始, 在Xcode中打開Grimm.xcodeproj. 點擊Main.storyboard你會看到下面的視圖:

你能夠忽略最開始的controller, 它是APP的根導航控制器. 依次點擊帶有編號的控制器, 你將看到以下內容:

  • 第一個控制器是StoryListController, 它是數據庫中全部故事的列表.
  • 點擊列表中的一個故事, 未來到StoryViewController, 它展現了點擊故事的標題和具體內容.
  • OptionsController是包含在StoryViewController控制器中的, 展現了支持的字體, 文本對其方式, 顏色等. 若想展現它, 只需點擊詳情頁右上角省略號的按鈕.

編譯並運行, 你將看到下面的初始畫面:

探索下APP, 選擇不一樣的故事, 點擊省略號按鈕, 滑動選擇不用的字體和閱讀模式, 以便理解這些用戶界面是如何工做的.

一旦你理解了該APP是如何工做的, 就直接進入下一部分. 向該APP添加模糊效果吧.

使用UIVisualEffectView添加模糊效果

UIKit提供了一整套視覺效果.UIBlurEffect(它是UIVisualEffect的子類), 是和你的興趣相關的.UIBlurEffect提供了很漂亮的視覺效果, 就像你在navigation bars,Notification Center,Control Center中看到的那樣. 你也能夠將其用到你的APP中.

添加UIBlurEffect

在這個工程中, 你將使用模糊效果使OptionsController在故事的頂部顯得更加突出.讓咱們投入其中吧!

打開OptionsController.swift, 添加下面的代碼到viewDidLoad:方法的結尾處:

// 1
view.backgroundColor = .clear
// 2
let blurEffect = UIBlurEffect(style: .light)
// 3
let blurView = UIVisualEffectView(effect: blurEffect)
// 4
blurView.translatesAutoresizingMaskIntoConstraints = false
view.insertSubview(blurView, at: 0)
複製代碼

依次解釋下:

  1. 爲了可以讓UIVisualEffectView視圖內容模糊起來, 它的父視圖必須是透明的. 爲了作到這點, 你將self.view的背景改爲了clear
  2. 使用UIBlurEffectStyle.light建立了一個UIBlurEffect. 這定義了模糊的風格. 其餘支持的風格還有.extraLight,.dark, .extraDark, regular, prominent(實際上我並無找到extraDark).
  3. 使用上一步建立的UIBlurEffect來建立UIVisualEffectView. 它是 UIView的子類.它惟一的目的是描繪複雜模糊的外形和顯示它.
  4. 關閉了blurViewauto-resizing而使用constraints, 稍後你將手動添加constraints到它上面. 添加它到視圖棧的底端. 若你在頂端添加blurView, 這將使下面的全部元素變得模糊.

如今, 你要肯定blurView被安放在合適的位置.添加下面的代碼到viewDidLoad:方法的結尾處:

NSLayoutConstraint.activate([
  blurView.heightAnchor.constraint(equalTo: view.heightAnchor),
  blurView.widthAnchor.constraint(equalTo: view.widthAnchor),
  ])
複製代碼

這些約束使blurViewframeOptionsController的view是同樣的.

編譯並運行, 選擇一個故事, 點擊省略號的按鈕, 滾動文本, 你會發現模糊效果在實時的更新.

如今, 你在你的APP中實現了一個動態的模糊效果, 它不只實現簡單, 並且看上去很漂亮.

使你的模糊效果更有活力

模糊效果很好, 但Apple使用UIVibrancyEffect將其帶入了下一個等級, 使用它可使內容色彩更生動.

以下圖:

注意: UIVibrancyEffect必須添加到UIVisualEffectViewcontentView中(它已經被正確放置, 使用UIBlurEffect配置過的)!不然不會向任何模糊的效果上添加"生動效果".

打開OptionsController.swift, 添加下面的代碼到viewDidLoad:方法的結尾處:

// 1
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
// 2
let vibrancyView = UIVisualEffectView(effect: vibrancyEffect)
vibrancyView.translatesAutoresizingMaskIntoConstraints = false
// 3
vibrancyView.contentView.addSubview(optionsView)
// 4
blurView.contentView.addSubview(vibrancyView)
複製代碼

依次解釋下:

  1. 使用以前配置好的blurEffect建立一個UIVibrancyEffect. UIVibrancyEffectUIVisualEffect的另外一個子類.
  2. 建立一個UIVisualEffectView用來包含UIVibrancyEffect效果. 這個步驟和以前建立模糊效果是同樣的. 一旦你使用了Auto Layout, 肯定將auto-resizing關閉.
  3. optionsView做爲vibrancyView中contentView的子視圖. 這將確保生動效果應用到其包含的每個元素中.
  4. 最後, 將vibrancyView添加到blurView的contentView中, 完成最終的效果.

接下來, 你要爲vibrancyView設置自動佈局的約束, 以便和blurView的尺寸同樣, 以及確保optionsView在vibrancyView的中心位置.

添加下面的代碼到viewDidLoad:方法的結尾處:

NSLayoutConstraint.activate([
  vibrancyView.heightAnchor.constraint(equalTo: blurView.contentView.heightAnchor),
  vibrancyView.widthAnchor.constraint(equalTo: blurView.contentView.widthAnchor),
  vibrancyView.centerXAnchor.constraint(equalTo: blurView.contentView.centerXAnchor),
  vibrancyView.centerYAnchor.constraint(equalTo: blurView.contentView.centerYAnchor)
  ])

NSLayoutConstraint.activate([
  optionsView.centerXAnchor.constraint(equalTo: vibrancyView.contentView.centerXAnchor),
  optionsView.centerYAnchor.constraint(equalTo: vibrancyView.contentView.centerYAnchor),
  ])
複製代碼

你還有一個事情須要注意, 看下viewDidLoad:的開始部分, 你以及將optionsView做爲self.view的子視圖了, 而一個視圖只能有一個父視圖.

viewDidLoad:的開始部分註釋掉下面的代碼:

view.addSubview(optionsView)
NSLayoutConstraint.activate([
  view.centerXAnchor.constraint(equalTo: optionsView.centerXAnchor),
  view.centerYAnchor.constraint(equalTo: optionsView.centerYAnchor)
  ])
複製代碼

編譯並運行, 你將看到新的效果已經生效:

除非有較大差別的版本, 不然這個效果會各個元素難以辨認. 這發生了什麼?

告訴你吧! 在blurView下一層的視圖是偏亮的, 而又使用了UIBlurEffectStyle.light的效果. 這將拔苗助長, 就像上面的效果.

修改初始化blurEffect的代碼以下:

let blurEffect = UIBlurEffect(style: .dark)
複製代碼

這個改變使背景和文字又來較大的差別.編譯運行, 你將看到下面的效果:

更進一步

在使用模糊效果時, 還有最後一點須要注意: 若是用戶將模糊效果禁用了, 將會發生什麼?

在模擬器或你的設備中, 打開設置, 進入General\Accessibility\Increase Contrast, 打開Reduce Transparency.(真機中應該是 通用\輔助功能\加強對比度\下降透明度 開關).返回到這個APP中, 再次打開optionsView, 你將看到下面的結果:

能夠看到它沒有正常工做. 這種狀況下, 你最好回到開始的地方.

幸運的是, 你可使用UIAccessibilityIsReduceTransparencyEnabled()方法判斷輔助功能是否打開.你能夠像下面這樣修改:

guard UIAccessibilityIsReduceTransparencyEnabled() == false else {
  view.addSubview(optionsView)
      
  NSLayoutConstraint.activate([
    view.centerXAnchor.constraint(equalTo: optionsView.centerXAnchor),
    view.centerYAnchor.constraint(equalTo: optionsView.centerYAnchor)
    ])
      
  return
}
複製代碼

OK, That's all!

多說一句, 你能夠進入UIAccessibility類中, 看看能夠檢測哪些開關的狀態的.

結語

整個過程當中, 最大的感觸是國內外的文風相差不是一丁半點啊. 國外的偏向故事風格有木有. 收穫仍是很多的, 感謝你們的陪伴, 讓咱們一塊兒進步!

  • 部分圖片來源於網絡,若有侵權,請告知。
  • 若有錯誤,還請指出。共勉!
  • 您的喜歡是最大的讚揚。
相關文章
相關標籤/搜索