-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMenuBar.swift
141 lines (109 loc) · 5.42 KB
/
MenuBar.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//
// MenuBar.swift
// MenuBar
//
// Created by Stela Sadova on 23.07.19.
// Copyright © 2019 Stela Sadova. All rights reserved.
//
import UIKit
@objc protocol MenuBarDelegate: AnyObject {
/// Called when the selected menu item changes
///
/// - Parameters:
/// - menuBar: The menu bar instance that triggered this call.
/// - index: The current index of the menu bar.
func menuBar(_ menuBar: MenuBar, didSelect index: Int)
}
@objc class MenuBar: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
@IBOutlet weak var delegate: MenuBarDelegate?
private lazy var collectionView: UICollectionView = {
let cv = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
cv.backgroundColor = .clear
cv.dataSource = self
cv.delegate = self
return cv
}()
private var menuItems = ["Menu Item", "Menu Item"]
@objc var items: Array<String>? {
didSet {
if let newItems = items, newItems.count > 1 {
menuItems = newItems
collectionView.reloadData()
if let sliderWidthAnchorConstraintUnwrapped = sliderWidthAnchorConstraint,
let newConstraint = sliderWidthAnchorConstraintUnwrapped.constraintWithMultiplier(1/CGFloat(menuItems.count)) {
self.removeConstraint(sliderWidthAnchorConstraintUnwrapped)
self.addConstraint(newConstraint)
self.layoutIfNeeded()
sliderWidthAnchorConstraint = newConstraint
}
} else {
assertionFailure("Menu items not set or less than 2")
}
}
}
private var sliderLeftAnchorConstraint: NSLayoutConstraint?
private var sliderWidthAnchorConstraint: NSLayoutConstraint?
override var intrinsicContentSize: CGSize {
return UIView.layoutFittingExpandedSize
}
override init(frame: CGRect) {
super.init(frame: frame)
setupCollectionView()
setupSlider()
}
func setupCollectionView() {
collectionView.register(MenuCell.self, forCellWithReuseIdentifier: MenuCell.reuseIdentifier)
addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
collectionView.leadingAnchor.constraint(equalTo:self.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
collectionView.topAnchor.constraint(equalTo:self.topAnchor),
collectionView.bottomAnchor.constraint(equalTo:self.bottomAnchor)])
let selectedIndexPath = IndexPath(item: 0, section: 0)
collectionView.selectItem(at: selectedIndexPath, animated: false, scrollPosition: [])
}
func setupSlider() {
let sliderView = UIView()
sliderView.backgroundColor = .blue
sliderView.translatesAutoresizingMaskIntoConstraints = false
addSubview(sliderView)
sliderLeftAnchorConstraint = sliderView.leftAnchor.constraint(equalTo: self.leftAnchor)
sliderLeftAnchorConstraint?.isActive = true
sliderView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
sliderWidthAnchorConstraint = sliderView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1/CGFloat(menuItems.count))
sliderWidthAnchorConstraint?.isActive = true
sliderView.heightAnchor.constraint(equalToConstant: 4).isActive = true
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return menuItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MenuCell.reuseIdentifier, for: indexPath) as! MenuCell
cell.label.text = menuItems[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: frame.width / CGFloat(menuItems.count), height: frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func collectionView(_: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let x = CGFloat(indexPath.item) * frame.width / CGFloat(menuItems.count)
sliderLeftAnchorConstraint?.constant = x
UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.layoutIfNeeded()
}, completion: nil)
delegate?.menuBar(self, didSelect: indexPath.item)
}
}
extension NSLayoutConstraint {
func constraintWithMultiplier(_ multiplier: CGFloat) -> NSLayoutConstraint? {
guard let firstItem = self.firstItem else { return nil }
return NSLayoutConstraint(item: firstItem, attribute: self.firstAttribute, relatedBy: self.relation, toItem: self.secondItem, attribute: self.secondAttribute, multiplier: multiplier, constant: self.constant)
}
}