項目中經常遇到一些設計使用圓角,不得不說這樣的設計經常能夠為App的視圖潤色不少!
通常做法
對于代碼黨來說,很簡單的加上一行代碼就能夠搞定:
view.layer.cornerRadius = 5
對于 Storyboard 狂魔,一般情況下,很多人會先把視圖拉一個 IBOutlet 然后再到 awakeFromeNib:
或者 viewDidLoad:
方法中去設置圓角,代碼如下:
@IBOutlet weak var customView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
customView.layer.cornerRadius = 5
}
但是對代碼有一定潔癖的強迫癥患者來說,這樣的做法經常是要命的!實在無法忍受一個小小圓角都不能在IB中設置,需要另外單獨加一行代碼來完成,違背了低耦合,高內聚的原則。有人馬上提出建議,那就使用IB的運行時屬性(Runtime Attributes),有些新手可能對?它還不太熟悉:
這的確也是個不錯的方法,可以達到高內聚的效果。不過用過的人都知道,很容易就把 keyPath 拼寫錯,而且由于這個設置和其他屬性的設置分開,可讀性可以說很差很差。那有沒有什么好的方法呢?
最佳實踐
Xcode6之后運行時屬性升級到了 @IBInspectable ,利用這個我們可以給 UIView 添加一個屬性,然后就可以在IB中進行設置,例如我們想給 ViewController 添加一個數值到IB中設置,在上述代碼的最前面插入代碼:
@IBInspectable var customNumber: Int?
然后我們就能在屬性檢查器上看到如圖所示內容,很容易地對數值進行設置:
@IBInspectable 還支持以下類型屬性:
- Boolean
- Number
- String
- Point
- Size
- Rect
- Range
- Color
- Image
- nil
回到正題,我們視圖的圓角該怎么實現呢?也許你們馬上想到了繼承,實現一個 UIView 的基類,基類中添加圓角的 @IBInspectable 屬性。但這樣你馬上嗅到了不好的味道,你所有想要使用該屬性的視圖都要繼承自該基類,那豈不是更加麻煩!
其實最好的解決方法你應該心里有數,如果說在 Object-C 中給已有的類添加方法,你肯定馬上能想到 Category !不過可能有些人還沒不清楚應該如何在 Category 中添加屬性。由于這里我們用的是 Swift ,稍后我們再說OC中應該如何實現。 Swift 中應該使用 extension 來對 UIView 進行擴展,并且我們需要添加 @IBInspectable 來擴展屬性,所以我們需要同時實現 setter & getter ,創建一個命名為 UIView+O2CornerRadius.swift
的文件,代碼如下:
import UIKit
extension UIView {
@IBInspectable var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
// also set(newValue)
set {
layer.cornerRadius = newValue
}
}
}
只需要如此簡單地添加一個擴展,不需要 import ,不必任何多余代碼,我們就可以非常非常方便地在任意IB的屬性檢查器中對圓角進行設置了!這不就是我們夢寐以求的解耦嗎?!!:)
實際上, @IBInspectable 是對運行時的一種擴展,你所有的設置都會在上述提到的運行時屬性(Runtime Attributes)有所體現。
接下來做什么?
我們還可以增加很多內容的擴展,例如陰影、邊框、邊框顏色等等!學會了這樣的奇淫技巧,還不趕緊到你的項目中去實踐!
說說 Object-C 的代碼實現,我們使用 Category 同樣需要同時實現 setter & getter :
//UIView+O2CornerRadius.h
@interface UIView (O2CornerRadius)
@property (nonatomic, assign) IBInspectable CGFloat cornerRadius;
@end
//UIView+O2CornerRadius.m
@implementation UIView (O2CornerRadius)
- (void)setCornerRadius:(CGFloat)cornerRadius
{
self.layer.cornerRadius = cornerRadius;
}
- (CGFloat)cornerRadius
{
return self.layer.cornerRadius;
}
@end