使用Swift在Xcode中創建自定義控件
IBDesignable and IBInspectable
With IBDesignable and IBInspectable, developers are allowed to create interface (or view) that renders in Interface Builder in real time. In general, to apply this new feature, all you need to do is create a visual class by subclassing UIView or UIControl and then prefix the class name with @IBDesignable keyword in Swift. If you are using Objective-C, you use IB_DESIGNABLE macro instead. Here is a sample code in Swift:
使用IBDesignable以及IBInspectable,開發者們被允許創建界面(或視圖),在Interface Builder中實時渲染。通常,運用這個特性,你需要做的就是繼承UIView或者UIControl的一個虛擬子類,然后在Swift中使用@IBDesignable
關鍵字進行標識。如果你使用Objective-C,你可以使用IB_DESIGNABLE宏代替。下面是一段加單的Swift示例代碼:
@IBDesignable
class Rainbow: UIView {
}
In older versions of Xcode, you can edit the user-defined runtime attributes to change properties of an object (e.g. layer.cornerRadius) in Interface Builder. The problem is you have to key in the exact name of the properties. IBInspectable takes a step forward. When you prefix a property of the visual class with IBInspectable, the property will be exposed to the Interface Builder such that you can change its value in a much straightforward way:
在老版本的Xcode中,你可以在Interface Builder中編輯user-defined
運行時屬性來修改一個對象的特性(如:layer.cornerRadius
。IBInspectable
前進了一步。當你在一個虛擬子類前面使用IBInspectable
關鍵字標識的時候,屬性將會暴露給Interface Builder,這樣你就可以使用一種非常直接的方式來修改它的值。
Again if you are developing your app in Swift, what you have to do is just prefix your chosen property with the keyword @IBInspectable. Here is a sample code snippet:
如果你使用Swift開發你的應用,你需要做的僅僅是標識出@IBInspectable
。下面是一個簡單的示例代碼段:
@IBInspectable var firstColor: UIColor = UIColor.blackColor() {
// Update your UI when value changes
}
Building Your Xcode Project
Let’s get started by creating a new project in Xcode and choose Single View Application as a template, and name it RainbowDemo. We will use Swift in this project as the programming language, so don’t forget to choose it when creating the project.
讓我們從在Xcode中創建一個新的項目並選擇SingleViewApplication模板開始,然后明明它為RainbowDemo
。我們將在這個項目中使用Swfit作為開發語言,所以在創建項目的時候不要忘記選擇語言。
Once finished, select the Main.storyboard in the Project Navigator and drag a View object from the Object Library to the View Controller. Change its color to #38334C (or whatever color you want) as well as set its size to 600 by 434. Then put it in the center of the main view. Don’t forget to change the color of the main view to the same color of the view object.
創建成功后,在項目導航中選擇Main.storyboard
,然后從對象庫中拖拽一個視圖對象到視圖控制器。修改它的顏色為#38334C
,以及設置它的尺寸為600*434。然后把它放到主視圖的中間。不要忘記修改主視圖的顏色與視圖對象的顏色一致。
With Xcode 6, you have to configure auto layout constraints for the view in order to support all types of iOS devices. Auto Layout is pretty powerful in the latest version of Xcode. For simple constraints, you can just click the Issues option of the Auto Layout menu and choose “Add Missing Contraints”, and Xcode will automatically configure the layout constraints for the view.
使用Xcode6,你需要為這個視圖配置自動布局常量,以便支持全部的iOS設備。在最新一版本的Xcode中,自動布局(Auto Layout)是非常有力的。對於簡單的約束,你可以僅僅點擊自動布局菜單中的Issues
並選擇“Add Missing Contraints”,然后Xcode將為視圖自動配置布局約束。
Creating Custom View Class
Now that you’ve created the view in storyboard, it’s time to create our custom view class. We’ll use the Swift class template for the class creation. Name it “Rainbow”.
現在,你已經在Storyboard中創建了視圖,是時候創建我們的自定義視圖類了。我們將使用Swift類模板來創建類。命名它為“Rainbow”。
Then insert the following code in the class:
然后在類中插入下面的代碼:
import UIKit
class Rainbow: UIView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
}
As mentioned before, the visual class is a subclass of UIView. In order to use our custom class in live rendering, we need to override both initializers as shown above. Next split the view by selecting the assistant editor:
就像上面提到的,這個虛擬類是UIView的子類。為了在渲染的時候使用我們的自定義類,我們需要重載上面呈現的代碼。然后通過選擇輔助編輯器來分割視圖:
Once done, select the main storyboard in the assistant editor, so you can see what you are building in real time. Remember to change the class name of the view to “Rainbow” under the Identity inspector:
一旦完成,在輔助編輯器中選擇Main.storyboard
,然后你可以看到你實時創建的東西。記得在Identity Inspector
中更改視圖的類名為Rainbow
:
Implementing IBDesignable Controls
The first step to enable a control for live rendering is to set the custom view as Designable by prefixing the class name with @IBDesignable:
啟用控件的實時渲染的第一步是通過給類名加上@IBDesignable
前綴來設置自定義視圖為Designable
。
@IBDesignable
class Rainbow: UIView {
...
}
It’s kinda simple as you can see. But this simple keyword would make your development much easier. Next, we will add a few properties for setting the colors of the circles. Insert these lines of code in the Rainbow class:
這就像你看到的一樣簡單。但是這個簡單的關鍵字將使你的開發非常的容易。下一步,我們將添加一些屬性來設置圈的顏色。在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)
Here, we predefine each property with a default colour, and tell it to redraw the view each time a user changes its value. Most importantly, we prefix each property with the @IBInspectable keyword. If you go to the Attributes inspectable of the view, you should find these properties visually:
這里,我們使用默認的顏色來預定義每一個屬性,然后告訴他,在用戶每一次更改它的值的時候重繪視圖。最重要的是,我們給每一個屬性都加上@IBIspectable
關鍵字。如果你查看視圖的屬性指示器,你將找到這些視覺屬性:
Cool, right? By indicating the properties as IBInspectable, you can edit them visually using color picker.
很酷,對么?通過標識屬性為IBInspectable
,你可以使用顏色選取器來編輯他們。
Okay let’s move to implement the main methods of the Rainbow class, which is used to draw a circle on the screen. Insert the following method in the class:
讓我們開始實現Rainbow
類用於在屏幕上繪制圓圈的主要方法。在類中插入下面的方法:
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)
}
To make the code clean and readable, we create a common method for drawing a full or half circle according to the parameters provided by the caller. It’s pretty straightforward to draw a circle or an arc using CAShapeLayer class. You can control the start and end of the stoke using the strokeStart and strokeEnd properties. By varying the value of stokeEnd between 0.0 and 1.0, you can draw a full or partial circle. The rest of the properties are just used to set the color of a stroke, shadow color, etc. You can check out the official documentation for details of all the properties available in CAShapeLayer.
為了使代碼干凈且可讀,我們創建一個公共的方法根據調用者傳入的參數來來繪制一整個或半個圓。它使用CAShapeLayer
類漂亮地直接繪制一個圓或一個圓弧。你可以使用strokeStart
以及strokeEnd
屬性來控制線的起點和終點。通過控制strokeEnd
的值在0.0與1.0之間,你可以繪制一整個或部分圓。剩下的屬性僅用於設置線的顏色、陰影顏色等。你可以在官方文檔中查看在CAShapeLayer
中可用的屬性的細節。
Next, insert the following methods in the Rainbow class:
接下來,插入下面的代碼到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)
}
The default implementation of the drawRect method does nothing. In order to draw circles in the view, we override the method to implement our own drawing code. The addCircle method takes in three parameters: arcRadius, capRadius and color. The arcRadius is the radius of the circle, while the capRadius is the radius of the rounded cap.
drawRect
函數的默認實現什么都不做。為了在視圖中繪制圓,我們重載這個函數來實現我們自己的繪制代碼。addCircle
方法使用三個參數:arcRadius
、capRadius
、color
。arcRadius
是圓的半徑,capRadius
是圓型覆蓋的半徑。
The addCircle method makes use of UIBezierPath to draw the arcs and it works like this:
- First it draws a half circle at the bottom
- Next it draws a full small circle at the edge of the arc.
- Finally, it draws the other half of the circle
addCircle
函數使用UIBezierPath
來繪制圓弧,並且它像這樣工作:
- 首先,繪制一個半圓在底部。
- 然后,繪制一整個小圓在弧的邊界。
- 最后,繪制這個圓的加一半。
In the drawRect method, we call the addCircle method three times with different radius and color. This figure illustrates how the circles are drawn:
在drawRect
函數中,我們使用不同的半徑與顏色調用addCircle
函數三次。這個特點闡述這些圓如何被繪制:
With the IBInspectable properties, you are now free to change the color of each circle right in the Interface Builder without diving into the code:
使用IBInspectable
屬性,你現在可以在Interface Builder中自由地正確修改每一個圓,而不用沉浸在代碼中。
Obviously, you can further expose arcRadius as an IBInspectable property. I’ll leave it as an exercise for you.
顯然地,你可以更深入的挖掘arcRadius
作為一個IBInspectable
屬性。
Summary
After going through this tutorial, I hope that you now understand how to use both IBDesignable and IBInspectable in Xcode 6. With the real-time preview in the Interface Builder, this new feature would allow you to create custom componenents in a more effcient way.
在隨着這個教程做完之后,我希望你可以理解如何使用IBDesignable
和IBInspectable
在Xcode6當中。利用在Interface Builder的實時預覽,新的特性允許你使用一種高效的方式創建自定義組件。
For your reference, you can download the complete Xcode project from here. As always, leave me comment and share your thought about the tutorial.
為了便於你參考,你可以從這里下載完整的Xcode項目。