I have been changing some code over from using frames to using auto layout and I've hit a small snag
for background I have been building a calendar, my issue is in the calendar's Day view which I have been trying to make so that it replicates apple's calendar.
This app has been sat in my hard drive since 2018 so is somewhat out of date, but in 2018 it did the following:
Displayed Events
by creating an EventContainerView
and placing it onto of a TableView
(not as a cell).
events which existed at the same time would shorten their width to prevent the container views from overlapping.
this last part is where my problem lies.
I did this by taking the width of the tableView, dividing it by the number of overlapping events and then multiplying it by a shiftBy
variable to shift the event to the right
for the life of me I cannot see a way to implement this with autoLayout.
before 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)
}
After AutoLayout
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
Can anybody offer up any suggestions as to how I might implement this piece of code?
Thanks
EDIT
this is what I'm trying to achieve (I took this on macOS's calendar but it still clearly show's how I want calendar events to appear)
and this is what I have (The darker yellow between 15 and 16 is another event stacked underneath the "Test Everything" event. I need one of them to shift over (along with any other events that may or may not be added to the same time frame)
Many different ways to approach this, but to make it close to what you were doing...
You can create equal width views that span a width, using a fixed spacing between them and a specific "padding" on each side, by:
Then, constrain the Width of each view equalTo the width of the previous view.
Here's a quick example:
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
}
}
The result, using 1, 2, 3 or 4 "events":
You should be able to adapt that to your needs.