在日常開發中,一個App會有很多模塊中的小模塊相差不多。這時候我們就需要考慮公用 -- 自定義View , 這樣就可以避免很多重復的代碼。
有哪些需要考慮的
- 首先要考慮不同的調用,純代碼的方式或者Xib 、Storyboard的方式都要可以使用
- 要有一定的可定制化 ,也就是暴露出來的屬性
- 使用起來簡單
實例
例如有這樣的 View
在不同的地方有用到。
截圖
很簡單的一個視圖,圖片加文字加邊框。
首先,新建一個UIView
的子類ImageTextView
, 在class前面添加open
關鍵字 (我們要做成公用的)
刪除drawRect相關方法,將下面代碼復制進去
public override init(frame: CGRect) {
super.init(frame: frame)
#if !TARGET_INTERFACE_BUILDER // 非interfabuilder環境下
// 如果是從代碼層面開始使用Autolayout,需要對使用的View的translatesAutoresizingMaskIntoConstraints的屬性設置為false
translatesAutoresizingMaskIntoConstraints = false
#endif
prepareView()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepareView()
}
// 布局
func prepareView(){
}
init?(coder:)
是從Xib或者Storyboard創建的時候會調用。 其他看注釋咯 - _ -
為UIImageView
添加一個擴展,方便創建UIImageView
對象
extension UIImageView {
class func configuredImageView() -> UIImageView {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFill
return imageView
}
}
回到ImageTextView
中聲明圖片和文本的變量
fileprivate let imageView = UIImageView.configuredImageView()
fileprivate lazy var textLabel = UILabel()
在prepareView
中對圖片和文本進行布局
// 布局
func prepareView(){
textLabel.translatesAutoresizingMaskIntoConstraints = false
textLabel.font = UIFont.systemFont(ofSize: CGFloat(textSize))
addSubview(imageView)
addSubview(textLabel)
imageView.setContentCompressionResistancePriority(1000, for: .horizontal )
NSLayoutConstraint.activate([
imageView.leftAnchor.constraint(equalTo: leftAnchor, constant:10 ) ,
imageView.centerYAnchor.constraint(equalTo: centerYAnchor) ,
textLabel.leftAnchor.constraint(equalTo: imageView.rightAnchor , constant:2 ) ,
textLabel.centerYAnchor.constraint(equalTo: centerYAnchor) ,
textLabel.rightAnchor.constraint(equalTo: rightAnchor, constant:-10)
])
layer.borderColor = UIColor.lightGray.cgColor
layer.borderWidth = 0.5
layer.cornerRadius = 3
}
這里的布局方法是iOS 9 開始支持的API , 當然你也可以使用SnapKit
為了使我們的View
可以在 InterfaceBuilder
中使用,在類前面使用注解 @IBDesignable
并暴露出可以自定義的屬性
extension ImageTextView{
@IBInspectable
open var image:UIImage?{
get{
return imageView.image
}
set{
imageView.image = newValue
}
}
@IBInspectable
open var text:String?{
get{
return textLabel.text
}
set{
textLabel.text = newValue ?? ""
}
}
@IBInspectable
open var textColor:UIColor? {
get{
return textLabel.textColor
}
set{
textLabel.textColor = newValue
}
}
}
在變量聲明下面在加上字體大小
// 這里使用 textSize 是因為 IBInspectable 暫時還不支持 UIFont
@IBInspectable
open var textSize:UInt = 17 {
didSet{
textLabel.font = UIFont.systemFont(ofSize: CGFloat(textSize))
}
}
這塊由于暫時不支持UIFont
所以使用了UInt
我們還可以在InterfaceBuilder
渲染前做一些事情
override open func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
// interface builder 渲染前執行 不會影響真正運行效果
layer.borderColor = UIColor.lightGray.cgColor
layer.borderWidth = 0.5
layer.cornerRadius = 3
}
到這里,這個自定義View
就算完成了,看下載Storyboard中的使用吧
隨便拖一個UIView
修改Class屬性
截圖
保存后就可以看到這些屬性了
截圖
設置完成后 InterfaceBuilder
立刻會渲染出來
截圖
這里是我隨便設了幾個屬性
截圖
有了這個自定義的View
,那么在任何地方有相似效果,我們只需要像拖UILabel
一樣把他拖出來簡單的設置下屬性就好了(也可以通過手寫代碼創建)。當然,這只是一個簡單的demo,并沒有涉及到事件Layer以及動畫等,如果有興趣下次再講。