自动布局以编程方式划分视图宽度

AutoLayout divide width of view programatically

我一直在将一些代码从使用框架更改为使用自动布局,但遇到了一个小问题

作为背景,我一直在构建一个日历,我的问题出在我一直试图制作的日历的“日”视图中,以便它复制苹果的日历。

这个应用自 2018 年以来一直在我的硬盘中,所以有点过时了,但在 2018 年它做了以下事情:

通过创建 EventContainerView 并将其放置在 TableView 上(不是作为单元格)来显示 Events

同时存在的事件会缩短它们的宽度以防止容器视图重叠。

这最后一部分是我的问题所在。

我通过获取 tableView 的宽度,将其除以重叠事件的数量,然后将其乘以一个 shiftBy 变量来将事件向右移动来做到这一点

我这辈子都找不到用 autoLayout 实现它的方法。

自动布局之前

func drawEvent(_ event:Event, overlaps:Int, shiftBy:Int) -> EventContainerView{
....
....


let eventWidth = (tableView.frame.width - 30) / CGFloat(overlaps)
        
        let shift = eventWidth * CGFloat(shiftBy)
        var frame: CGRect
     if(shiftBy > 0){
         frame = CGRect(x: CGFloat(30 + (5*shiftBy)) + shift, y: startPoint, width: eventWidth, height: endpoint)
         
     }else{
         frame = CGRect(x: CGFloat(30) + shift, y: startPoint, width: eventWidth, height: endpoint)
         
     }

自动布局后

func drawEvent(_ event:Event, overlaps:Int, shiftBy:Int) -> EventContainerView{
....
....

let eventView = EventContainerView(forEvent: event, today: self)
           eventView.translatesAutoresizingMaskIntoConstraints = false
 var left: NSLayoutConstraint = eventView.leftAnchor.constraint(equalTo: tableView.leftAnchor, constant: +20)
   
    if(shiftBy>0){
        left = ????
    }
    
    tableView.addSubview(eventView)
        let layout = [eventView.topAnchor.constraint(equalTo: tableView.topAnchor, constant: startPoint),
        left,
        eventView.heightAnchor.constraint(equalToConstant: endpoint),
        eventView.widthAnchor.constraint(equalTo: tableView.widthAnchor, multiplier: 1/CGFloat(overlaps), constant: -30)]
    NSLayoutConstraint.activate(layout)
        return eventView

任何人都可以就我如何实现这段代码提出任何建议吗?

谢谢

编辑

这就是我想要实现的目标(我在 macOS 的日历上使用了它,但它仍然清楚地显示了我希望日历事件如何显示)

这就是我所拥有的(15 到 16 之间的深黄色是堆叠在“测试一切”事件下方的另一个事件。我需要其中一个转移(以及可能会或可能不会发生的任何其他事件)被添加到同一时间范围)

许多不同的方法来解决这个问题,但要使其接近您正在做的事情...

您可以创建跨越宽度的等宽视图,使用它们之间的固定间距和每边的特定“填充”,方法是:

  • 将第一个视图的行距限制为父视图的行距+填充
  • 将每个连续视图的前导限制为前一个视图的尾随 + 间距
  • 将最后一个视图的尾部限制为父视图的尾部 - 填充

然后,限制每个视图的宽度等于前一个视图的宽度。

这是一个简单的例子:

class AndyViewController: UIViewController {

    let numEvents = 1
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // a var to track the previously added view
        var prevView: UIView!
        
        var startPoint: CGFloat = 100
        
        // create a couple eventViews
        for i in 0..<numEvents {
            let thisView = eventView()
            view.addSubview(thisView)
            
            // set top constraint
            thisView.topAnchor.constraint(equalTo: view.topAnchor, constant: startPoint).isActive = true
            
            // let's pretend each view is 20-pts "later"
            startPoint += 20.0
            
            // for now, make them all 50-pts tall
            thisView.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
            
            // if it's the first view
            if i == 0 {
                // constrain its leading to view leading + 30
                thisView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30.0).isActive = true
            } else {
                // make sure prevView has been set
                guard let pv = prevView else {
                    fatalError("Did something wrong!!!")
                }
                // start this view at the right-end of the previous view + 5
                thisView.leadingAnchor.constraint(equalTo: prevView.trailingAnchor, constant: 5.0).isActive = true
                // make this view width equal to previous view width
                thisView.widthAnchor.constraint(equalTo: pv.widthAnchor).isActive = true
            }
            
            // if it's the last view
            if i == numEvents - 1 {
                // constrain its trailing to view trailing -30
                thisView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
            }
            
            // set prevView to thisView
            prevView = thisView
        }
        
    }

    func eventView() -> UIView {
        let v = UIView()
        v.backgroundColor = UIColor.yellow.withAlphaComponent(0.8)
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }
    
}

结果,使用 1、2、3 或 4 个“事件”:

您应该能够根据自己的需要进行调整。