Created
May 7, 2020 09:36
-
-
Save Jimmy-Prime/8f6b5ebefcf7f0269c4cddeadbbd2326 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
class ViewController: UIViewController { | |
var yearView: UIView? | |
var currentYear: Int = 2020 { | |
didSet { | |
createYearView() | |
} | |
} | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.backgroundColor = .systemBackground | |
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "-", style: .plain, target: self, action: #selector(minus)) | |
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "+", style: .plain, target: self, action: #selector(add)) | |
createYearView() | |
} | |
func createYearView() { | |
yearView?.removeFromSuperview() | |
let yearView = YearView(year: currentYear) | |
view.addSubview(yearView) | |
yearView.translatesAutoresizingMaskIntoConstraints = false | |
NSLayoutConstraint.activate([ | |
yearView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), | |
yearView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), | |
yearView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), | |
yearView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor) | |
]) | |
self.yearView = yearView | |
} | |
@objc private func minus() { | |
currentYear -= 1 | |
} | |
@objc private func add() { | |
currentYear += 1 | |
} | |
} | |
class TitleGridView: UIView { | |
private let titleLabel = UILabel() | |
private let items: [[UIView]] | |
let rows: Int | |
let columns: Int | |
var interval: CGPoint = .zero | |
var spaceUnderTitle: CGFloat = 0 | |
init(rows: Int, columns: Int, titleConfiguration: (UILabel) -> Void, itemCreator: (Int, Int) -> UIView) { | |
self.rows = rows | |
self.columns = columns | |
items = (0..<rows).map { row in | |
(0..<columns).map { column in | |
itemCreator(row, column) | |
} | |
} | |
super.init(frame: .zero) | |
titleConfiguration(titleLabel) | |
addSubview(titleLabel) | |
items.forEach { $0.forEach { addSubview($0) } } | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override func layoutSubviews() { | |
titleLabel.frame = CGRect(x: 0, y: 0, width: frame.width, height: titleLabel.intrinsicContentSize.height) | |
let firstRowY = titleLabel.frame.maxY + spaceUnderTitle | |
let size = CGSize( | |
width: (frame.width - interval.x * CGFloat(columns - 1)) / CGFloat(columns), | |
height: (frame.height - firstRowY - interval.y * CGFloat(rows - 1)) / CGFloat(rows) | |
) | |
for (row, aRow) in items.enumerated() { | |
for (column, item) in aRow.enumerated() { | |
item.frame = CGRect( | |
x: CGFloat(column) * (size.width + interval.x), | |
y: CGFloat(row) * (size.height + interval.y) + firstRowY, | |
width: size.width, | |
height: size.height | |
) | |
} | |
} | |
} | |
} | |
class YearView: TitleGridView { | |
init(year: Int) { | |
let titleConfiguration = { (label: UILabel) in | |
label.font = .preferredFont(forTextStyle: .largeTitle) | |
label.text = String(year) | |
} | |
let itemCreator = { (row: Int, column: Int) in | |
MonthInYearView(year: year, month: row * 3 + column + 1) | |
} | |
super.init(rows: 4, columns: 3, titleConfiguration: titleConfiguration, itemCreator: itemCreator) | |
interval = CGPoint(x: 8, y: 4) | |
spaceUnderTitle = 4 | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
} | |
class MonthInYearView: TitleGridView { | |
init(year: Int, month: Int) { | |
let calendar = Calendar.current | |
let timeZone = TimeZone.current | |
let titleConfiguration = { (label: UILabel) in | |
label.font = .preferredFont(forTextStyle: .title2) | |
label.text = calendar.monthSymbols[month - 1] | |
} | |
let components = DateComponents(calendar: calendar, timeZone: timeZone, year: year, month: month) | |
let date = calendar.date(from: components)! | |
let firstWeekday = calendar.dateComponents(in: timeZone, from: date).weekday! - 1 | |
let range = calendar.range(of: .day, in: .month, for: date)! | |
let itemCreator = { (row: Int, column: Int) -> UILabel in | |
let label = UILabel() | |
label.textAlignment = .center | |
label.font = .systemFont(ofSize: 10) | |
let day = row * 7 + column + 1 - firstWeekday | |
if range.contains(day) { | |
label.text = String(day) | |
} | |
return label | |
} | |
super.init(rows: 6, columns: 7, titleConfiguration: titleConfiguration, itemCreator: itemCreator) | |
interval = CGPoint(x: 4, y: 3) | |
spaceUnderTitle = 4 | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment