FSCalendar使用代码动态约束,仿飞书/钉钉日历交互

3,157 阅读2分钟

最近在做仿飞书/钉钉日历的交互,主要交互如下:

  1. 页面的上方是日历(calendarView)
  2. 页面的下方是表格视图(tableView)
  3. 日历视图可以切换周/月状态,日历视图的底部与表格视图的顶部连接,当日历视图切换成周状态向上收起时,表格视图也跟着向上移动。

如下图:

画板@3x.png

找到了swift第三方日历库FSCalendar满足我需要的交互,但是无论是日历库的官方demo/document还是其他人的分享,在布局的时候使用的都是storyboard,在storyboard中添加约束。这不太符合我的要求:

  1. 我不想在自己的项目中使用storyboard,更喜欢纯代码布局
  2. 使用storyboard添加约束,后续如果有协作会有些不方便
  3. 页面会添加很复杂的交互,storyboard担心不好处理

基于以上,研究了一下如何代码添加约束达到我想要的约束效果,分享下经验。

  1. 创建日历视图和表格视图
    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
    }()
  1. 为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()
}