Swift 程式語言

CALayer 初學者指南:如何增加陰影效果、邊框、製作圓角

CALayer 初學者指南:如何增加陰影效果、邊框、製作圓角
CALayer 初學者指南:如何增加陰影效果、邊框、製作圓角
In: Swift 程式語言, UIKit

本篇文章將會談論iOS開發中的關鍵議題之一layers,它為Core Animation框架的一部份,雖然讀者可能已經接觸過iOS中的Views,卻可能不知道,每個View都是透過layer做為圖形繪製的基礎。

讀者可能會想「過去開發從未碰觸到layer,它重要嗎?」,但事實上,你開發的應用程式中,layer都扮演著重要的角色,因為每個View的圖形繪製都是由layer所支持,也是因為Layers的存在,所以iOS可以輕易從應用程式裡獲取View裡面的bitmap(點陣圖)資訊,提供給裝置中的圖像處理器,請看下列圖表(擷取自Apple ),顯示Core Animation位於iOS圖形繪製的層次結構中。

calayer-intro

為什麼需要Layers?

使用智慧手機裝置時,使用者都預期能夠處在一個順暢的操作環境中,因此,保持一致的幀率(描述視頻流更新的的頻率)是至關重要的一件事,如此才能確保提供使用者流暢的使用體驗,在iOS中,圖形處理器為每秒刷新60次的頻率,為了讓系統能維持在這個速率,一個非常基本卻強大的圖形功能layer被創造出來,並直接運行OpenGL這個圖形處理器。

OpenGL (Open Graphics Library,開放圖形庫)提供iOS圖性處理器最底層的(也是最快)訪問,但是,OpenGL就算處理極為簡單的需求,也必須透過大量的代碼去達成任務。

為了緩解這個問題,Core Graphics因運而生,它提供了較高階的功能,只需要更少的代碼就能達成任務。隨後,為了能更簡單的處理 Core Graphics的作業,再推出了Core Animation,它提供 CALayer 類別讓圖形處理器去接受部分底層的基本訪問需求。

儘管如此,蘋果仍考量許多應用程式並不需要Core Animation提供的進階圖形繪製功能,所以打造了UIKit這個應用層,它在iOS開發中,提供最高階的APIs給開發者直接使用,換句話說,UIKit的推出提供另一項選擇,讓使用者根據自己的需求選取所需的方案,不必在多寫不必要的程式碼。

但這存在一些劣勢,高階APIs在作業上也相對沒有彈性,無法滿足開發中的需求,這也告訴我們,雖然大部分的情況都不需要直接接觸到CALayer,但是CALayer提供較底層的APIs,讓開發者能更彈性的做出自己想要的功能,CALayer的存在,使得iOS可以快速且輕易在應用程式的View層次結構中抓取bitmap資訊,丟給Core Graphics進行下一步作業,最終由OpenGL處理後呈現至裝置螢幕上,這篇文章將會帶讀者初步探索它。

探索CALayer

上面的篇幅已經大致講述為何會有layers存在,現在就一同探索它吧!就如同文章一開始所說,每個View都是透過layer做為圖形繪製的基礎,可以在UIView的屬性中訪問layer,若是你有myView這個物件,也可以透過下列的語法,對layer進行存取。

myView.layer

那我們訪問layer之後可以做些什麼呢?本文接下來的篇幅將帶讀者去探究相關的應用,你可能會感到很驚訝,原來它可以做到這麼多事情。

Demo Project

首先,請下載這個範例starter project,我們將會在這個app中,針對layers進行一些客製化的效果展示,最好的學習方法,則是跟上腳步一起實作。現在我們打開這個範例,你可以看到目前架構相當簡單,一個白色的view中間包含一個正方形的subview,讓我們來美化一下它,請點開ViewController.swift準備接下來的作業。

calayer-ib

製作圓角

你可以更改CALayer中的屬性cornerRadius,藉此得到圓角的圖形,請在viewDidLoad()裡面輸入下方這行程式碼。

box.layer.cornerRadius = 5

就像我們所預期,這行程式碼將會對這個box的layer,增加corner radius的屬性,我們將5賦值給它以後,正方形的四個角會變成圓角,就像下列這張圖。

calayer-corner-radius-1

效果看起來還不錯,若是將數值提高,則圓角的效果將會更趨顯著,反之亦然,若是沒有特別設定,corner radius的預設值為0。

calayer-corner-radius

增加陰影效果

陰影效果可以讓我們在app裡設計UI更有彈性,接下來,將透過CALayer來製作陰影效果,請在 ViewController裡面的viewDidLoad添加下列這段程式碼

box.layer.shadowOffset = CGSizeMake(5, 5)
box.layer.shadowOpacity = 0.7
box.layer.shadowRadius = 5
box.layer.shadowColor = UIColor(red: 44.0/255.0, green: 62.0/255.0, blue: 80.0/255.0, alpha: 1.0).CGColor

Line #1:: 第一行是賦值給layer shadow offset,呼叫 CGSize塞入所需數值給layer.shadowOffset這個屬性, 傳送(5, 5)給layer.shadowOffset表示layer的陰影顯示在box.layer右側及下方5points的距離。

Line #2:: 第二行則是設定layer shadow的透明度,0.7代表將透明度將是原先的70%

Line #3:: 第三行為設定layer的陰影範圍為5,數值越高則陰影越模糊且分散,數值越低則會較清晰且集中。

Line #4: 第四行則是將陰影的顏色設定為深藍色,但請注意這邊的屬性特定是針對 CGColor,而不是UIColor,若是要進行轉換也很簡單,只要輸入myUIColor.CGColor即可。

讓我們看一下更改屬性後的效果

calayer-shadow

邊框應用

CALayer 也讓開發者可以很輕易的對box的邊框進行設定

box.layer.borderColor = UIColor.blueColor().CGColor
box.layer.borderWidth = 3

Line #1: 第一行是將box的邊框顏色設定為深藍色

Line #2: 第二行則是將box的邊框寬度設定為3,賦值後box將會出現厚度3 points的邊框。

添加上述的box邊框設定後如下圖

calayer-border

展示圖片

開發者也可以將一張圖片嵌進layer,讓layer呈現這張圖片的樣子,在我們的範例中,將會透過一張樹木的圖片進行展示,圖片來源自此網站,接下來,就讓我們透過一個layer去展示這張圖片,請於viewDidLoad貼入下列代碼。

box.layer.contents = UIImage(named: "tree.jpg")?.CGImage
box.layer.contentsGravity = kCAGravityResize
box.layer.masksToBounds = true

Line #1: 第一行我們先宣告一個UIImage,並且將檔案名稱為tree.jpg的檔案寫入,賦值給layer屬性中的contents

Line #2: 第二行程式碼是將這個圖層的屬性contentsGravity設定為resize,設置後layer裡面的內容會被重新調整對齊,完美地貼合layer。

Line #3: 第三行masksToBounds屬性若被設置為true,會將超過邊筐外的sublayers裁切掉,若是不理解這個屬性效果為何,可以將屬性設置為false,比較兩者不同之處。

請參考下面的對照圖

calayer-images-masktobounds

背景顏色以及透明度

我們先前談論到如何透過 CALayer添加想要的特效,但我們也應該知道,大部分修改的 UIKit屬性,是來自UIViewCALayer元件。舉例來說,開發者可藉由下列程式碼,更改View的背景顏色與透明度。

box.layer.backgroundColor = UIColor.blueColor().CGColor
box.layer.opacity = 0.5

CALayer效能表現

添加過多額外的效果會將會影響效能,但現在我們將談到兩個CALayer的屬性,可以幫助開發者改善應用程式的效能表現。

首先,來談談異步繪製(drawsAsynchronously),它可以指定CPU是否讓繪製作業在背景進行,若是異步繪製被設定為true,CPU進行繪製作業將在背景線程運作,如果你的應用程式需要頻繁進行重新繪製得作業,例如地圖或tableview頁面,那開發者應該開啟異步繪製的設定。

下一個屬性是shouldRasterize,這個屬性在CALayer中,將可指定layer是否 rasterized(點陣化,將對象轉換成對應像素點的過程),若是這屬性被設置為true,layer將會被重新繪製。但請注意,當這個對象是一個動畫,它不會被重繪,且bitmap資訊會在首次繪製時就被回收。因此,這個特性應該在應用程式不會頻繁進行重繪作業時,才被設置為true
此外,由於CALayer 在建立完畢之後,預設都是一倍解析度,若在Retina裝置中變更shouldRasterize屬性設定,可能看起來會糊糊的,為了防止出現這個問題,應該要告訴 CALayer 用怎樣的解析度,將rasterizationScale 設置為UIScreen.mainScreen().scale

還是要提醒讀者,在開發的99%時間裡面,並不會需要自己去設定上述的這些屬性,手動更改可能會影響到app的運作效能,因此,只有在已經確定視圖繪製會如何影響應用程式效能表現的時候,再考慮手動更改上述這兩項屬性的預設值。

結論

現在你已經知道什麼是CALayer,對於繪圖底層知識有更多一點的了解後,將可以幫助你打造更酷炫的apps,希望讀者享受本篇CALayer初心者指南。

讀者可以在GitHub 下載完整Xcode項目作參考。 如果有任何問題或是回饋,歡迎踴躍在下方留言。

譯者簡介:陳奕先-過去為平面財經記者,專跑產業新聞,2015年起跨進軟體開發世界,希望在不同領域中培養新的視野,於新創學校ALPHA Camp畢業後,積極投入iOS程式開發,目前任職於國內電商公司。聯絡方式:電郵[email protected]

FB : https://www.facebook.com/yishen.chen.54
Twitter : https://twitter.com/YeEeEsS

原文A Beginner’s Guide to CALayer

作者
Pranjal Satija
現時為高中生,喜歡在課餘時間創作App,享受把創作App的經驗與人分享。除此之外還喜歡滑雪、高爾夫球、足球,與朋友在一起。
評論
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。