I am drawing a line on screen to anchor to the bottom of an FSCalendar, nothing special however the line appears in different positions on different devices (attempting with a physical iPhone 11 Pro and a couple different simulators. If I get it at the right position on one device it will appear a bit to high or to low on another. Any ideas as to why this might happen?
My code for the line is as follows (the leading and trailing positions are rendering fine)...
extension UIView {
let bottom: CGFloat {
return self.frame.size.height + self.frame.origin.y
}
let leading: CGFloat {
return self.frame.origin.x
}
let trailing: CGFloat {
return self.frame.size.width + self.frame.origin.x
}
}
class CalendarViewController: UIViewController {
@IBOutlet var calendar: FSCalendar!
override func viewDidLoad() {
drawCalendarSeperatorLine()
}
private func drawCalendarSeperatorLine() {
let path = UIBezierPath()
let yPosition: CGFloat = calendar.bottom
let xLeading = view.leading + 15
let xTrailing = view.trailing - 15
path.move(to: CGPoint(x: xLeading, y: yPosition))
path.addLine(to: CGPoint(x: xTrailing, y: yPosition))
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.separator.cgColor
shapeLayer.lineWidth = 1
shapeLayer.opacity = 0.7
view.layer.addSublayer(shapeLayer)
}
}
Frames are not completely laid-out in viewDidLoad()
.
You could move your call to viewDidLayoutSubviews()
:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
drawCalendarSeperatorLine()
}
however, viewDidLayoutSubviews()
can, and very often will, be called multiple times (such as on device rotation), and your func will be adding a new sublayer every time.
Another (probably better approach) would be to add a 1-pt high view, constrained to the bottom of calendarView
.
So, in viewDidLoad()
you can do this:
override func viewDidLoad() {
super.viewDidLoad()
let sepView = UIView()
sepView.backgroundColor = UIColor.separator.withAlphaComponent(0.7)
sepView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(sepView)
NSLayoutConstraint.activate([
sepView.leadingAnchor.constraint(equalTo: calendar.leadingAnchor, constant: 15.0),
sepView.trailingAnchor.constraint(equalTo: calendar.trailingAnchor, constant: -15.0),
sepView.topAnchor.constraint(equalTo: calendar.bottomAnchor),
sepView.heightAnchor.constraint(equalToConstant: 1.0),
])
}
Now you'll have your "separator line" at the bottom of the calendar view, and it will "stick" to the bottom and resize its width if/when the calendar view frame changes.