自Xcode 6 開始,iOS開發人員可以利用 IBDesignable 和 IBInspectable 功能建構客製化 control 並即時在 Interface Builder 預覽變更。很明顯的,這是一個提升生產力的巨大優勢。
在這個單元裡面,我們將為大家介紹 IBDesignable 和 IBInspectable,並且向大家展示如何來利用這個新功能。要瞭解並學習一個新的功能,除了建立一個Demo程式來學習之外,我認為應該沒有其他更好的方式了。所以,在本章節我們將一起建立一個名為Rainbow
客製化介面來學習本章的內容。
IBDesignable 和 IBInspectable
隨著 IBDesignable 和 IBInspectable的推出,開發人員被允許可以建立interface (或view) 並即時地顯示在Interface Builder內。 在一般情況下,要應用這個新功能,在Swift裡面你只需要建立新的類別並繼承自UIView或UIControl的類別,然後在建立的新類別名稱前面加上一個@IBDesignable的前綴字串即可。 如果你使用的是Objective-C,你需要使用IB_DESIGNABLE
來代替。 Swift的範例程式如下
@IBDesignable
class Rainbow: UIView {
}
在舊版本的Xcode,你可以編輯一個使用者預先定義的runtime屬性來更改Interface Builder內原先物件的屬性。(如:layer.cornerRadius
) 。但問題是,你必須事先知道這個屬性的確切名稱。隨著IBInspectable出現又往前邁進了一步。你可以透過IBInspectable預先定義一個可視化的物件(visual class)的屬性。而這個屬性將會直接顯示在Interface Builder內,所以你可以用更直覺的方式來變更這個屬性的參數:
同樣的,如果你正在使用Swift開發一個app,你要做的只是輸入也要變更的屬性並在前面加入@IBInspectable
的前綴字串,示範程式如下:
@IBInspectable var firstColor: UIColor = UIColor.blackColor() {
// Update your UI when value changes
}
是不是感到有點困惑了呢? 不用擔心。當我們完成這個demo的專案,你將會明白我的意思。
建立你的Xcode專案
就讓我們開始建立這個專案吧,首先我們在Xcode開啟一個新的專案並且選擇Single View Application當作範本,然後輸入RainbowDemo
當作專案的名稱。對了,我們將使用Swift為這個專案的語言,所以當專案建立時別忘了選擇它。
完成後,透過專案導覽列(Project Navigator)選擇專案裡面的Main.storyboard,然後從元件Library裡面內拖曳一個新的view元件裡面到View Controller內。 並且調整新的view元件的顏色為#38334C
(或任何你喜歡的顏色) 並且改變view物件的尺寸為600×343。接著將這個view元件置中存放在main view。 最後別忘了變更main view的顏色與view物件一樣。
在Xcode 6,你必須為view元件要配置Auto layout constraint來支援所有iOS裝置內螢幕尺寸不同的問題。 Auto Layout在最新版本的Xcode非常強大。要建立簡單的constraints,你只要在Auto Layout 選單立面點選 Issues 的提示符號,並且選擇 Add Missing Constraints 的選項,然後Xcode將會為view自動建立必須的layout constraints。
建立客製化的View類別
現在我們已經在storyboard建立了view,現在是時候來建立我們的客製化view class了。 我們將使用Swift類別當做這個類別的範本。然後命名為Rainbow
。
接著在類別下面插入如下的代碼:
import UIKit
class Rainbow: UIView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
}
如前之前提到的,這個可視類別是UIView
的子類。 為了使我們的客製化類別能夠被即時的預覽,我們需要override 這兩個 initializers如下所示。 下一步我們將透過選擇 assistant editor切換至view內:
接著,在assistant editor內選擇main storyboard,之後你便可以即時的看到你在建構的元件。請記住,你必須在Identity inspector下面改變view的class name為Rainbow
:
實體化IBDesignable Controls
第一步 開啟控制器的的即時預覽,我們需要設定客製化的view為Designable透過添加@IBDesignable
前綴字串在我們的類別名稱之前:
@IBDesignable
class Rainbow: UIView {
...
}
是的,就是如你看到的這麼簡單。 但是,這個簡單的關鍵字將讓你的往後再開發上變得更加容易。下一步,我們將會為我們即將添加的圓型添加一些顏色屬性。 我們在Rainbow 類別下面插入下面的代碼:
@IBInspectable var firstColor: UIColor = UIColor(red: (37.0/255.0), green: (252.0/255), blue: (244.0/255.0), alpha: 1.0)
@IBInspectable var secondColor: UIColor = UIColor(red: (171.0/255.0), green: (250.0/255), blue: (81.0/255.0), alpha: 1.0)
@IBInspectable var thirdColor: UIColor = UIColor(red: (238.0/255.0), green: (32.0/255), blue: (53.0/255.0), alpha: 1.0)
在上面的代碼裡,我們先預訂每個屬性都有預設的顏色,然後在使用者變更數值之後他將會告訴它告訴view需要進行圖形的重新繪製。最重要的事,我們替每個屬性加上@IBInspectable
的前綴關鍵子。 所以如果你前往Attributes inspectable去進行檢視,你應該可以看到這些我們客製化的數屬性可以在Interface Builder下直接檢視:
很酷吧? 透過指定屬性為IBInspectable,你可以直覺地使用顏色選擇器直接進行編輯。
我們接著來建置Rainbow class的主要功能,為了能在螢幕上產生一個圓型。 我們在類別裡面插入如下的代碼:
func addOval(lineWidth: CGFloat, path: CGPathRef, strokeStart: CGFloat, strokeEnd: CGFloat, strokeColor: UIColor, fillColor: UIColor, shadowRadius: CGFloat, shadowOpacity: Float, shadowOffsset: CGSize) {
let arc = CAShapeLayer()
arc.lineWidth = lineWidth
arc.path = path
arc.strokeStart = strokeStart
arc.strokeEnd = strokeEnd
arc.strokeColor = strokeColor.CGColor
arc.fillColor = fillColor.CGColor
arc.shadowColor = UIColor.blackColor().CGColor
arc.shadowRadius = shadowRadius
arc.shadowOpacity = shadowOpacity
arc.shadowOffset = shadowOffsset
layer.addSublayer(arc)
}
為了增加程式碼的乾淨性跟易讀性,我們建置了一個共用方法來根據使用者所提供的參數來繪製半圓型或者一整個圓型。我們利用CAShapeLayer
類別可以用很省力的方式來完成繪製一個圓型或圓弧型的工作。你可以使用strokeStart和strokeEnd屬性來控筆觸的起點和終點。 通過改變stokeEnd
的值(介於0.0和1.0之間),可以得出一個完整的圓型或部分的圓弧型。其他的屬性則用來設定筆觸的顏色,陰影的顏色,等等。 你可以閱讀官方文件檔案 來獲得關於CAShapeLayer
所有屬性以及更多的相關的細節。
接著,插入下面的方法在Rainbow類別內:
override func drawRect(rect: CGRect) {
// Add ARCs
self.addCirle(80, capRadius: 20, color: self.firstColor)
self.addCirle(150, capRadius: 20, color: self.secondColor)
self.addCirle(215, capRadius: 20, color: self.thirdColor)
}
func addCirle(arcRadius: CGFloat, capRadius: CGFloat, color: UIColor) {
let X = CGRectGetMidX(self.bounds)
let Y = CGRectGetMidY(self.bounds)
// Bottom Oval
let pathBottom = UIBezierPath(ovalInRect: CGRectMake((X - (arcRadius/2)), (Y - (arcRadius/2)), arcRadius, arcRadius)).CGPath
self.addOval(20.0, path: pathBottom, strokeStart: 0, strokeEnd: 0.5, strokeColor: color, fillColor: UIColor.clearColor(), shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
// Middle Cap
let pathMiddle = UIBezierPath(ovalInRect: CGRectMake((X - (capRadius/2)) - (arcRadius/2), (Y - (capRadius/2)), capRadius, capRadius)).CGPath
self.addOval(0.0, path: pathMiddle, strokeStart: 0, strokeEnd: 1.0, strokeColor: color, fillColor: color, shadowRadius: 5.0, shadowOpacity: 0.5, shadowOffsset: CGSizeZero)
// Top Oval
let pathTop = UIBezierPath(ovalInRect: CGRectMake((X - (arcRadius/2)), (Y - (arcRadius/2)), arcRadius, arcRadius)).CGPath
self.addOval(20.0, path: pathTop, strokeStart: 0.5, strokeEnd: 1.0, strokeColor: color, fillColor: UIColor.clearColor(), shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)
}
預設實體化時drawRect
方法是不會執行任何結果。 為了在view裡面能繪製圓圈,我們需要override現有drawRect方法來實現我們自己的繪製代碼。在addCircle
有三個參數: arcRadius
,capRadius
和 color
。 arcRadius
是圓型的內圍的半徑circle,而capRadius
圓型外圍的半徑(也就是圓型線條寬度)。
在addCircle
方法裡面,我們利用了UIBezierPath
來繪製弧形,他的運作原理如下:
- 首先,他繪製了半圈底部
- 在接下來它繪製一個完整的小圓弧形的邊緣
- 最後,繪製圓的另一半
在drawRect
方法裡面,我們呼叫了剛剛建立的addCircle
方法三次,來繪製不同顏色的圓型。下面的圖形說明了圓型的繪製過程:
有了IBInspectable屬性,你可以自由的在Interface Builder改變每個圓圈的顏色而不需要撰寫程式碼:
很明顯的,你可以進一步的擴展 arcRadius
成為IBInspectable 屬性。 我將指派他當作你的練習題。
總結
在經歷了這個教學課程之後,我希望你能明白你能了解IBDesignable和IBInspectable在Xcode 6裡面的使用方式。 隨著Interface Builder可以透過本文的方式來近行及時的預覽,這將提供一個更有效率的方法來建立客製化的元件(componenents)。
供你參考,從這裡 下載完整的Xcode project。 一如往常的,請你給我一些回應並且分享關於這篇教學文章的各種想法。
原文:Creating Your Own Custom Controls Using IBDesignable in Xcode 6