编程约束折叠单元视图

时间:2016-07-05 20:19:38

标签: ios swift uitableview constraints

我正在开发一个以xib开头的UITableViewCell,以编程方式添加视图,并具有动态大小的高度。但是,在使用约束添加程序视图时,它与最初应用于xib的自动调整大小约束相冲突,并导致问题。请参阅以下内容:

让我的细胞出列:

//Table Delegate/Datasource
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    var cell:S360SSessionMatchTableCell? = tableView.dequeueReusableCellWithIdentifier(XIBFiles.SESSIONMATCHTABLECELL + String(indexPath.row)) as? S360SSessionMatchTableCell

    if ((cell == nil)){
        tableView.registerNib(UINib(nibName: XIBFiles.SESSIONMATCHTABLECELL, bundle: nil), forCellReuseIdentifier: XIBFiles.SESSIONMATCHTABLECELL + String(indexPath.row))
        cell = tableView.dequeueReusableCellWithIdentifier(XIBFiles.SESSIONMATCHTABLECELL + String(indexPath.row)) as? S360SSessionMatchTableCell
    }

    cell!.setupEvents(sessionMatches[indexPath.row]["sessions"]! as! [[String:String]])

    return cell!
}

自定义UITableViewCell中的设置事件方法:

func setupEvents(events:[[String:String]]){

    //Set up start and end times
    self.startTimeLbl.text = events[0]["startTime"]!
    self.endTimeLbl.text = events[events.count - 1]["endTime"]!

    //Set up events
    var pastEventView:S360SScheduledEventView? = nil
    var pastEvent:[String:String]? = nil
    for (index, event) in events.enumerate(){
        var topAnchor:NSLayoutConstraint!

        //Create event view
        let eventView:S360SScheduledEventView = NSBundle.mainBundle().loadNibNamed(XIBFiles.SCHEDULEDEVENTVIEW, owner: self, options: nil)[0] as! S360SScheduledEventView

        //Deal with first view added
        if pastEvent == nil{

            //Top anchor setup for first view
            topAnchor = NSLayoutConstraint(item: eventView, attribute: .Top, relatedBy: .Equal, toItem: toLbl, attribute: .Bottom, multiplier: 1, constant: 10)
        }
        else{

            //Check for a break
            let timeFormatter:NSDateFormatter = NSDateFormatter()
            timeFormatter.dateFormat = "hh:mm a"
            let startTime = timeFormatter.dateFromString(pastEvent!["endTime"]!)
            let endTime = timeFormatter.dateFromString(event["startTime"]!)
            if startTime != endTime {

                //Create break view
                let breakView = NSBundle.mainBundle().loadNibNamed(XIBFiles.SCHEDULEDBREAKVIEW, owner: self, options: nil)[0] as! S360SScheduledBreakView

                //Setup breakview constraints
                let bTopAnchor = NSLayoutConstraint(item: breakView, attribute: .Top, relatedBy: .Equal, toItem: pastEventView, attribute: .Bottom, multiplier: 1, constant: 0)
                let bLeftAnchor = NSLayoutConstraint(item: breakView, attribute: .Leading, relatedBy: .Equal, toItem: self.contentView, attribute: .LeadingMargin, multiplier: 1, constant: 0)
                let bRightAnchor = NSLayoutConstraint(item: breakView, attribute: .Trailing, relatedBy: .Equal, toItem: self.contentView, attribute: .TrailingMargin, multiplier: 1, constant: 0)
                let bHeightAnchor = NSLayoutConstraint(item: breakView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 30)

                //Add break view and constraints
                self.addSubview(breakView)
                self.addConstraints([bTopAnchor, bLeftAnchor, bRightAnchor, bHeightAnchor])

                //Top anchor setup for subsequent view
                topAnchor = NSLayoutConstraint(item: eventView, attribute: .Top, relatedBy: .Equal, toItem: breakView, attribute: .Bottom, multiplier: 1, constant: 0)
            }
            else{

                //Top anchor setup for subsequent views
                topAnchor = NSLayoutConstraint(item: eventView, attribute: .Top, relatedBy: .Equal, toItem: pastEventView, attribute: .Bottom, multiplier: 1, constant: 0)
            }

        }

        //Setup other anchors
        let leftAnchor = NSLayoutConstraint(item: eventView, attribute: .Leading, relatedBy: .Equal, toItem: self.contentView, attribute: .LeadingMargin, multiplier: 1, constant: 0)
        let rightAnchor = NSLayoutConstraint(item: eventView, attribute: .Trailing, relatedBy: .Equal, toItem: self.contentView, attribute: .TrailingMargin, multiplier: 1, constant: 0)
        let heightAnchor = NSLayoutConstraint(item: eventView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 60)

        //Setup event view
        eventView.iconImg.image = Images.get_event_image(event["title"]!)
        eventView.titleLbl.text = event["title"]!
        eventView.courtLbl.text = "court" + event["court"]!
        eventView.timeLbl.text = event["startTime"]! + " to " + event["endTime"]!

        //Add event view and constraints
        self.addSubview(eventView)
        self.addConstraints([topAnchor, leftAnchor, rightAnchor, heightAnchor])

        //Prepare for next iteration
        pastEventView = eventView
        pastEvent = event

        //Set up last cell with bottom bound
        if index == events.count - 1 {
            let bottomAnchor = NSLayoutConstraint(item: eventView, attribute: .Bottom, relatedBy: .Equal, toItem: self.contentView, attribute: .BottomMargin, multiplier: 1, constant: 0)
            self.addConstraint(bottomAnchor)
        }

    }
}

xib中的约束: enter image description here

这是我得到的错误(粘贴一次,但每个单元格都会出现):

   Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2016-07-05 15:13:01.654 Shoot360 Scheduler[32779:642808] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
    (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x7fedd85d5590 h=--& v=--& V:[UITableViewCellContentView:0x7fedda431120(44)]>",
    "<NSLayoutConstraint:0x7fedda43a7e0 V:[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda438b20(60)]>",
    "<NSLayoutConstraint:0x7fedda436590 UITableViewCellContentView:0x7fedda431120.topMargin == UILabel:0x7fedda4312a0'10:00 AM'.top - 15>",
    "<NSLayoutConstraint:0x7fedda436630 UILabel:0x7fedda431c00'to'.top == UILabel:0x7fedda4312a0'10:00 AM'.top>",
    "<NSLayoutConstraint:0x7fedda433b60 V:[UILabel:0x7fedda431c00'to']-(10)-[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda438b20]>",
    "<NSLayoutConstraint:0x7fedda445910 V:[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda4443f0(60)]>",
    "<NSLayoutConstraint:0x7fedda448310 V:[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda438b20]-(0)-[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda4443f0]>",
    "<NSLayoutConstraint:0x7fedda449a00 V:[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda448540(60)]>",
    "<NSLayoutConstraint:0x7fedda4479e0 V:[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda4443f0]-(0)-[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda448540]>",
    "<NSLayoutConstraint:0x7fedda44a100 Shoot360_Scheduler.S360SScheduledEventView:0x7fedda448540.bottom == UITableViewCellContentView:0x7fedda431120.bottomMargin>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fedda436590 UITableViewCellContentView:0x7fedda431120.topMargin == UILabel:0x7fedda4312a0'10:00 AM'.top - 15>

行高设置为动态:

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        //Styling
        showAllBtn.layer.cornerRadius = Numbers.CORNERRADIUS

        sessionsTbl.rowHeight = UITableViewAutomaticDimension
        sessionsTbl.estimatedRowHeight = 500
        sessionsTbl.layer.borderColor = Colors.REALLIGHTGREY.CGColor
        sessionsTbl.layer.borderWidth = Numbers.BORDERREG
        sessionsTbl.layer.cornerRadius = Numbers.CORNERRADIUS
        sessionsTbl.separatorStyle = UITableViewCellSeparatorStyle.None
    }

 func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }

2 个答案:

答案 0 :(得分:1)

约束

  

N:[UITableViewCellContentView:0x7fedda431120(44)

表示当您希望单元格高度为动态时,表格中的rowHeight设置为默认值44pt。您必须将rowHeight设置为UITableViewAutomaticDimension并设置estimatedRowHeight

另请注意,重复使用单元格,因此每次调用setupEvents时都必须删除所有以前添加的视图。

另请注意,您不应该从tableView.registerNib(...)方法中调用cellForRow。注册单元格的好地方是viewDidLoad

答案 1 :(得分:0)

你似乎已经让自己的生活变得更加复杂。

如果我们看一下你现在拥有的东西:

  1. 包含1个部分和多行
  2. 的表格
  3. 1个细胞亚类
  4. 每行都有随意添加的任意数量的子视图
  5. 每个子视图都使用约束
  6. 相互固定
  7. 每个单元都为每一行显式实例化,未正确重用
  8. 单元格在重复使用时没有删除子视图
  9. 这不适合表格视图,这意味着您正在编写大量代码并尝试将其全部填充到一个位置。

    查看您的数据最好有类似的内容:

    1. 包含多个部分的表格,每个部分都有多行
    2. 每节一节
    3. 每个'事件'一行
    4. 带有日期标签的1节标题类
    5. 2个单元格子类,1个用于事件,1个用于休息
    6. 暂时没有添加视图
    7. 在这种情况下,您的约束是微不足道的,并且在代码中没有添加约束,您只需设置一些数据,其他一切都可以正常工作。该方案还打破了您的顾虑,并将每个不同部分的代码分离为逻辑部分。

      您应该退一步看看您的方法,而不是尝试修复现有问题。