SnapKit(自动布局)的作用同SDAutoLayout、Masonry(前身), 通过约束实现控件的自动布局; 比StoryBoard的优点是代码实现, 维护起来比较方便(复杂界面多个人协作)。 我觉得iOS的自动布局很像是Android里的RelativeLayout, 通过跟父控件、子控件、兄弟控件的相对关系确定最终的大小和位置。
GtiHub地址:https://github.com/SnapKit/SnapKit
使用Cocoapod引用到工程里:
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'SnapkitTest' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
pod ’SnapKit’, ‘~> 3.2.0’
# Pods for SnapkitTest
target 'SnapkitTestTests' do
inherit! :search_paths
# Pods for testing
end
target 'SnapkitTestUITests' do
inherit! :search_paths
# Pods for testing
end
end
在Swift文件头添加import SnapKit即可。
SnapKit的使用方法: 使用snp.makeConstraint方法添加约束, 包括:边距、宽、高、上下左右距离; SnapKit还支持删除约束、更新约束等, 以及相对位置(inset,offset)和倍率修正(multipleBy和divideBy)。
SnapKit支持如下属性:
视图属性(ViewAttribute) | 布局属性(NSLayoutAttribute) |
view.snp.left | NSLayoutAttribute.Left |
view.snp.right | NSLayoutAttribute.Right |
view.snp.top | NSLayoutAttribute.Top |
view.snp.bottom | NSLayoutAttribute.Bottom |
view.snp.leading | NSLayoutAttribute.Leading |
view.snp.trailing | NSLayoutAttribute.Trailing |
view.snp.width | NSLayoutAttribute.Width |
view.snp.height | NSLayoutAttribute.Height |
view.snp.centerX | NSLayoutAttribute.CenterX |
view.snp.centerY | NSLayoutAttribute.CenterY |
view.snp.baseline | NSLayoutAttribute.Baseline |
首页2个按钮:
button1?.snp.makeConstraints{ make in
make.width.equalTo(140)
make.height.equalTo((button1?.snp.width)!).multipliedBy(0.3) //通过宽高比例得出值,类似于Android的layout_weight
make.centerX.equalTo(self.view.center.x) //横向居中
make.top.equalTo(100)
}
button2?.snp.makeConstraints({ make in
make.width.equalTo(140)
make.height.equalTo((button2?.snp.width)!).multipliedBy(0.3)
make.centerX.equalTo(self.view.center.x)
make.top.equalTo(button1!.snp.bottom).offset(20) //相对位置,纵向按钮间距
})
先调用addSubView方法后才能设置约束! 通过上面示例看出Snapkit的使用方法很简单, 就是实现一个闭包。
点击按钮切换到下一个界面时, 也可以通过代码方式实现(另一种是在StoryBorad里设置)。
self.navigationController?.pushViewController(SimpleUseViewController(), animated: false)
点击“按钮1”显示1个红块和5个按钮, 点击5个按钮可以看出添加、删除、更新约束,还可以添加切换时的动画效果。
注意: 变更约束条件时必须用layoutIfNeede函数,强制刷新界面。
UIView.animate(withDuration: 1, animations: {
self.view.layoutIfNeeded() //强制刷新布局
})
class LineTableViewCell: UITableViewCell {
var icon: UIView? //圆圈图标
var name: UILabel?
var mobile: UILabel?
var desc: UILabel?
var container: UIView?
var comment: UILabel?
let gapHori: CGFloat = 20 //横向间距
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
initViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func initViews() {
name = UILabel()
name?.font = UIFont.systemFont(ofSize: 20)
name?.textColor = UIColor.black
name?.text = "姓名"
name?.sizeToFit() //填充文本,不用宽高。等同于Android的wrap_content
self.contentView.addSubview(name!)
name?.snp.makeConstraints{ make in
make.top.equalTo(contentView).offset(15)
make.left.equalTo(contentView).offset(40)
}
icon = UIView()
icon?.backgroundColor = UIColor.orange
icon?.layer.cornerRadius = 5
icon?.layer.masksToBounds = true
self.contentView.addSubview(icon!)
icon?.snp.makeConstraints{ make in
make.top.equalTo(contentView).offset(15)
make.left.equalTo(contentView).offset(gapHori)
make.width.height.equalTo(10)
make.centerY.equalTo((name?.snp.centerY)!)
}
mobile = UILabel()
mobile?.font = UIFont.systemFont(ofSize: 14)
mobile?.textColor = UIColor.black
mobile?.text = "手机号码"
mobile?.sizeToFit()
self.contentView.addSubview(mobile!)
mobile?.snp.makeConstraints{ make in
make.top.equalTo(self.contentView).offset(15)
make.left.equalTo(name!.snp.right).offset(gapHori)
make.centerY.equalTo((name?.snp.centerY)!)
}
desc = UILabel()
desc?.font = UIFont.systemFont(ofSize: 12)
desc?.textColor = UIColor.black
desc?.numberOfLines = 1 //最多1行
desc?.lineBreakMode = .byTruncatingTail //超过边界时显示...
desc?.sizeToFit()
desc?.text = "描述"
self.contentView.addSubview(desc!)
desc?.snp.makeConstraints{ make in
make.top.equalTo((name?.snp.bottom)!).offset(10)
make.left.equalTo((name?.snp.left)!)
make.right.equalTo(contentView).offset(-10)
}
//类似在Android ViewGroup里添加一个TextView
container = UIView()
container?.backgroundColor = UIColor.lightGray
container?.layer.cornerRadius = 5
self.contentView.addSubview(container!)
container?.snp.makeConstraints{ make in
make.top.equalTo((desc?.snp.bottom)!).offset(10)
make.left.equalTo((desc?.snp.left)!)
make.right.equalTo(contentView).offset(-10)
make.bottom.equalTo(contentView).offset(-10)
}
comment = UILabel()
comment?.lineBreakMode = .byWordWrapping
comment?.font = UIFont.boldSystemFont(ofSize: 10)
comment?.textColor = UIColor.red
comment?.numberOfLines = 0 //0表示不限制行数
comment?.sizeToFit()
container?.addSubview(comment!)
comment?.snp.makeConstraints{ make in
make.edges.equalTo(container!).inset(UIEdgeInsetsMake(5, 5, 5, 5)) //跟父布局的边界,inset类似于android的padding
}
}
}