Swift - XIB结合UIView制作自定义组件(xib加载绘制UIView)
作者:hangge | 2016-10-12 09:00
我原来写过几篇文章,介绍如何通过继承 UIView 来实现自定义组件(见上方列表)。当时自定义组件是使用纯代码实现的。但是如果组件里的元素比较多,布局比较复杂。那用纯代码写就比较麻烦了。对于这种复杂的自定义组件,我们可以结合 XIB 文件来实现。
一、自定义组件的创建
这里还是同前文一样,实现一个简单的进度条组件。用户可以自由设置进度条的进度、尺寸、文字颜色、进度条颜色、背景颜色。不同的是,我们这里创建的时候引入 xib 文件来实现布局。

(1)新建一个自定义组件实现类 MyProgressBar( 继承 UIView)。由于是继承 UIView,“Also create XIB file”无法勾选。这个没关系,后面我们会手动创建一个 xib 文件并关联。

(2)再新建一个同名的 XIB 文件(带有 View)

(3)打开刚创建的 xib 文件,将 File's Owner 的 Custom Class 设置为我们自定义组件类的名字。
注意:修改的是 MyProgressBar.xib 中 File’s Owner 的 Custom Class,不要修改成 MyProgressBar.xib 里 View 的 Custom Class 了。

(4)将 xib 文件中 View 的 Size 修改为 Freedom,Status bar 修改为 None。并将其调整成合适的尺寸。

(5)在 View 中添加一个 UIView 和一个 UILabel,并设置好约束和相关属性。分别作为当前进度区块,以及当前进度标签。

(6)将上面添加的两个组件拖拽关联到 MyProgressBar.swift。并补充相关的组件实现代码,以及 xib 视图加载的相关代码。
MyProgressBar.swift 完整代码如下:
import UIKit
@IBDesignable class MyProgressBar: UIView {
//显示进度的文本标签
@IBOutlet weak var textLabel: UILabel!
//显示当前进度区域
@IBOutlet weak var bar: UIView!
//进度
@IBInspectable var percent: Int = 0 {
didSet {
if percent > 100 {
percent = 100
}else if percent < 0 {
percent = 0
}
textLabel.text = "\(percent)%"
setNeedsLayout()
}
}
//文本颜色
@IBInspectable var color: UIColor = .white {
didSet {
textLabel.textColor = color
}
}
//进度条颜色
@IBInspectable var barColor: UIColor = UIColor.orange {
didSet {
bar.backgroundColor = barColor
}
}
//进度条背景颜色
@IBInspectable var barBgColor: UIColor = UIColor.lightGray {
didSet {
layer.backgroundColor = barBgColor.cgColor
}
}
//初始化默认属性配置
func initialSetup(){
textLabel.text = "\(self.percent)%"
textLabel.textColor = self.color
bar.backgroundColor = self.barColor
layer.backgroundColor = self.barBgColor.cgColor
}
//布局相关设置
override func layoutSubviews() {
super.layoutSubviews()
var barFrame = bounds
barFrame.size.width *= (CGFloat(self.percent) / 100)
bar.frame = barFrame
}
/*** 下面的几个方法都是为了让这个自定义类能将xib里的view加载进来。这个是通用的,我们不需修改。 ****/
var contentView:UIView!
//初始化时将xib中的view添加进来
override init(frame: CGRect) {
super.init(frame: frame)
contentView = loadViewFromNib()
addSubview(contentView)
addConstraints()
//初始化属性配置
initialSetup()
}
//初始化时将xib中的view添加进来
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
contentView = loadViewFromNib()
addSubview(contentView)
addConstraints()
//初始化属性配置
initialSetup()
}
//加载xib
func loadViewFromNib() -> UIView {
let className = type(of: self)
let bundle = Bundle(for: className)
let name = NSStringFromClass(className).components(separatedBy: ".").last
let nib = UINib(nibName: name!, bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil).first as! UIView
return view
}
//设置好xib视图约束
func addConstraints() {
contentView.translatesAutoresizingMaskIntoConstraints = false
var constraint = NSLayoutConstraint(item: contentView, attribute: .leading,
relatedBy: .equal, toItem: self, attribute: .leading,
multiplier: 1, constant: 0)
addConstraint(constraint)
constraint = NSLayoutConstraint(item: contentView, attribute: .trailing,
relatedBy: .equal, toItem: self, attribute: .trailing,
multiplier: 1, constant: 0)
addConstraint(constraint)
constraint = NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal,
toItem: self, attribute: .top, multiplier: 1, constant: 0)
addConstraint(constraint)
constraint = NSLayoutConstraint(item: contentView, attribute: .bottom,
relatedBy: .equal, toItem: self, attribute: .bottom,
multiplier: 1, constant: 0)
addConstraint(constraint)
}
}
二、自定义组件的使用
通过 xib 创建的自定义组件与之前使用纯代码实现的自定义组件相比,在使用的时候是没什么区别的。
1,在代码中使用自定义组件
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let myProgressBar = MyProgressBar(frame: CGRect(x:50, y:50, width:200, height:20))
myProgressBar.percent = 50
self.view.addSubview(myProgressBar)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
2,在在StoryBoard中使用自定义组件
(1)打开Main.storyboard,从组件库里添加一个视图(View)

(2)在Identity Inspector里把视图类改成MyProgressBar

(3)可以看到自定义组件已经渲染显示出来了

(4)在Attributes inspector面板中可以调整组件的各个自定义属性

全部评论(2)
自定义控件的点击(或其他)事件如何监听呢
站长回复:可以在自定义组件里添加相关手势,比如:点击(UITapGestureRecognizer)、滑动(UISwipeGestureRecognizer)。然后通过代理在外面进行响应。
说实话这个网站对我帮助很大,很高兴看到一个引航灯式的教学平台
站长回复:我也很高兴能帮助到你。欢迎常来看看,我会一直创作更新下去的。