最近在做仿飞书/钉钉日历的交互,主要交互如下:
- 页面的上方是日历(calendarView)
- 页面的下方是表格视图(tableView)
- 日历视图可以切换周/月状态,日历视图的底部与表格视图的顶部连接,当日历视图切换成周状态向上收起时,表格视图也跟着向上移动。
如下图:
找到了swift第三方日历库FSCalendar满足我需要的交互,但是无论是日历库的官方demo/document还是其他人的分享,在布局的时候使用的都是storyboard,在storyboard中添加约束。这不太符合我的要求:
- 我不想在自己的项目中使用storyboard,更喜欢纯代码布局
- 使用storyboard添加约束,后续如果有协作会有些不方便
- 页面会添加很复杂的交互,storyboard担心不好处理
基于以上,研究了一下如何代码添加约束达到我想要的约束效果,分享下经验。
- 创建日历视图和表格视图
private lazy var calendarView:FSCalendar = {
let calendarV = FSCalendar()
calendarV.dataSource = self
calendarV.delegate = self
self.calendar = calendarV
return calendarV
}()
private lazy var tableView:UITableView = {
let tableV = UITableView()
tableV.delegate = self
tableV.dataSource = self
tableV.backgroundColor = UIColor.blue
tableV.separatorStyle = .none
tableV.dragInteractionEnabled = true
tableV.showsVerticalScrollIndicator = false
tableV.register(cellType: PPTaskPoolTableViewCell.self)
return tableV
}()
- 为calendarView和tableView添加约束
//添加日历视图
view.addSubview(calendarView)
//因为是手动添加布局。所以要关闭默认的自动布局,否则会报错
calendarView.translatesAutoresizingMaskIntoConstraints = false
//添加calendarView的顶部约束
let calendarTop:NSLayoutConstraint = NSLayoutConstraint(item: calendarView, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: kNavigationBarH)
self.view.addConstraint(calendarTop)
//添加calendarView的左侧约束
let calendarLeft:NSLayoutConstraint = NSLayoutConstraint(item: calendarView, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.leading,multiplier: 1, constant: 20)
self.view.addConstraint(calendarLeft)
//添加calendarView的右侧约束
let calendarRight:NSLayoutConstraint = NSLayoutConstraint(item: calendarView, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: -20)
self.view.addConstraint(calendarRight)
//添加calendarView的高度约束
let calendarHeight:NSLayoutConstraint = NSLayoutConstraint(item: calendarView, attribute: NSLayoutConstraint.Attribute.height, relatedBy:NSLayoutConstraint.Relation.equal, toItem:nil, attribute:NSLayoutConstraint.Attribute.notAnAttribute, multiplier:1.0, constant: 300)
calendarView.addConstraint(calendarHeight)
//添加表格视图
view.addSubview(tableView)
//关闭表格视图的默认自动布局
tableView.translatesAutoresizingMaskIntoConstraints = false
//添加tableView的顶部约束,因为需要一直跟calendarView的底部连接,所以toItem属性中写的是self.calendarView
let tableViewTop:NSLayoutConstraint = NSLayoutConstraint(item: tableView, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.calendarView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 20)
self.view.addConstraint(tableViewTop)
//添加tableView的左侧约束
let tableViewLeft:NSLayoutConstraint = NSLayoutConstraint(item: tableView, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.leading,multiplier: 1, constant: 0)
self.view.addConstraint(tableViewLeft)
//添加tableView的右侧约束
let tableViewRight:NSLayoutConstraint = NSLayoutConstraint(item: tableView, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: 0)
self.view.addConstraint(tableViewRight)
//添加tableView的底部约束
let tableViewBottom:NSLayoutConstraint = NSLayoutConstraint(item: tableView, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy:NSLayoutConstraint.Relation.equal, toItem:self.view, attribute:NSLayoutConstraint.Attribute.bottom, multiplier:1.0, constant: -20)
self.view.addConstraint(tableViewBottom)
最后,因为我是用snpkit做的整体布局,所以想要动态布局生效,需要添加框架中的方法
func calendar(_ calendar: FSCalendar, boundingRectWillChange bounds: CGRect, animated: Bool) {
calendar.snp.updateConstraints { (make) in
make.height.equalTo(bounds.height)
}
self.view.layoutIfNeeded()
}