4 // Created by Si MA on 03/01/2015.
5 // Copyright (c) 2015 Si Ma. All rights reserved.
11 Keys for segment properties
14 // This is mainly for the top/bottom margin of the imageView
15 let keyContentVerticalMargin = "VerticalMargin"
17 // The colour when the segment is under selected/unselected
18 let keySegmentOnSelectionColour = "OnSelectionBackgroundColour"
19 let keySegmentOffSelectionColour = "OffSelectionBackgroundColour"
21 // The colour of the text in the segment for the segment is under selected/unselected
22 let keySegmentOnSelectionTextColour = "OnSelectionTextColour"
23 let keySegmentOffSelectionTextColour = "OffSelectionTextColour"
25 // The font of the text in the segment
26 let keySegmentTitleFont = "TitleFont"
29 enum SegmentOrganiseMode: Int {
30 case segmentOrganiseHorizontal = 0
31 case segmentOrganiseVertical
35 protocol SMSegmentViewDelegate: class {
36 func segmentView(_ segmentView: SMSegmentView, didSelectSegmentAtIndex index: Int)
39 class SMSegmentView: UIView, SMSegmentDelegate {
40 weak var delegate: SMSegmentViewDelegate?
42 var indexOfSelectedSegment = NSNotFound
43 var numberOfSegments = 0
45 var organiseMode: SegmentOrganiseMode = SegmentOrganiseMode.segmentOrganiseHorizontal {
47 self.setNeedsDisplay()
51 var segmentVerticalMargin: CGFloat = 5.0 {
53 for segment in self.segments {
54 segment.verticalMargin = self.segmentVerticalMargin
60 var separatorColour: UIColor = UIColor.lightGray {
62 self.setNeedsDisplay()
65 var separatorWidth: CGFloat = 1.0 {
67 for segment in self.segments {
68 segment.separatorWidth = self.separatorWidth
70 self.updateFrameForSegments()
75 var segmentOnSelectionColour: UIColor = UIColor.darkGray {
77 for segment in self.segments {
78 segment.onSelectionColour = self.segmentOnSelectionColour
82 var segmentOffSelectionColour: UIColor = UIColor.white {
84 for segment in self.segments {
85 segment.offSelectionColour = self.segmentOffSelectionColour
90 // Segment Title Text Colour & Font
91 var segmentOnSelectionTextColour: UIColor = UIColor.white {
93 for segment in self.segments {
94 segment.onSelectionTextColour = self.segmentOnSelectionTextColour
98 var segmentOffSelectionTextColour: UIColor = UIColor.darkGray {
100 for segment in self.segments {
101 segment.offSelectionTextColour = self.segmentOffSelectionTextColour
105 var segmentTitleFont: UIFont = UIFont.systemFont(ofSize: 17.0) {
107 for segment in self.segments {
108 segment.titleFont = self.segmentTitleFont
113 override var frame: CGRect {
115 self.updateFrameForSegments()
119 var segments: Array<SMSegment> = Array()
121 required init?(coder aDecoder: NSCoder) {
122 fatalError("init(coder:) has not been implemented")
125 override init(frame: CGRect) {
126 super.init(frame: frame)
127 self.backgroundColor = UIColor.clear
128 self.layer.masksToBounds = true
131 init(frame: CGRect, separatorColour: UIColor, separatorWidth: CGFloat, segmentProperties: Dictionary<String, AnyObject>?) {
132 self.separatorColour = separatorColour
133 self.separatorWidth = separatorWidth
135 if let margin = segmentProperties?[keyContentVerticalMargin] as? Float {
136 self.segmentVerticalMargin = CGFloat(margin)
139 if let onSelectionColour = segmentProperties?[keySegmentOnSelectionColour] as? UIColor {
140 self.segmentOnSelectionColour = onSelectionColour
143 self.segmentOnSelectionColour = UIColor.darkGray
146 if let offSelectionColour = segmentProperties?[keySegmentOffSelectionColour] as? UIColor {
147 self.segmentOffSelectionColour = offSelectionColour
150 self.segmentOffSelectionColour = UIColor.white
153 if let onSelectionTextColour = segmentProperties?[keySegmentOnSelectionTextColour] as? UIColor {
154 self.segmentOnSelectionTextColour = onSelectionTextColour
157 self.segmentOnSelectionTextColour = UIColor.white
160 if let offSelectionTextColour = segmentProperties?[keySegmentOffSelectionTextColour] as? UIColor {
161 self.segmentOffSelectionTextColour = offSelectionTextColour
164 self.segmentOffSelectionTextColour = UIColor.darkGray
167 if let titleFont = segmentProperties?[keySegmentTitleFont] as? UIFont {
168 self.segmentTitleFont = titleFont
171 self.segmentTitleFont = UIFont.systemFont(ofSize: 17.0)
174 super.init(frame: frame)
175 self.backgroundColor = UIColor.clear
176 self.layer.masksToBounds = true
179 func addSegmentWithTitle(_ title: String?, onSelectionImage: UIImage?, offSelectionImage: UIImage?) {
181 let segment = SMSegment(
182 separatorWidth: self.separatorWidth,
183 verticalMargin: self.segmentVerticalMargin,
184 onSelectionColour: self.segmentOnSelectionColour,
185 offSelectionColour: self.segmentOffSelectionColour,
186 onSelectionTextColour: self.segmentOnSelectionTextColour,
187 offSelectionTextColour: self.segmentOffSelectionTextColour,
188 titleFont: self.segmentTitleFont
190 segment.index = self.segments.count
191 self.segments.append(segment)
192 self.updateFrameForSegments()
194 segment.delegate = self
195 segment.title = title
196 segment.onSelectionImage = onSelectionImage
197 segment.offSelectionImage = offSelectionImage
199 self.addSubview(segment)
201 self.numberOfSegments = self.segments.count
204 func updateFrameForSegments() {
205 if self.segments.count == 0 {
209 let count = self.segments.count
211 if self.organiseMode == SegmentOrganiseMode.segmentOrganiseHorizontal {
212 let segmentWidth = (self.frame.size.width - self.separatorWidth*CGFloat(count-1)) / CGFloat(count)
213 var originX: CGFloat = 0.0
214 for segment in self.segments {
215 segment.frame = CGRect(x: originX, y: 0.0, width: segmentWidth, height: self.frame.size.height)
216 originX += segmentWidth + self.separatorWidth
220 let segmentHeight = (self.frame.size.height - self.separatorWidth*CGFloat(count-1)) / CGFloat(count)
221 var originY: CGFloat = 0.0
222 for segment in self.segments {
223 segment.frame = CGRect(x: 0.0, y: originY, width: self.frame.size.width, height: segmentHeight)
224 originY += segmentHeight + self.separatorWidth
229 self.segments[0].frame = CGRect(x: 0.0, y: 0.0, width: self.frame.size.width, height: self.frame.size.height)
232 self.setNeedsDisplay()
235 // MARK: SMSegment Delegate
236 func selectSegment(_ segment: SMSegment) {
237 if self.indexOfSelectedSegment != NSNotFound {
238 let previousSelectedSegment = self.segments[self.indexOfSelectedSegment]
239 previousSelectedSegment.setSelected(false)
241 self.indexOfSelectedSegment = segment.index
242 segment.setSelected(true)
243 self.delegate?.segmentView(self, didSelectSegmentAtIndex: segment.index)
247 func selectSegmentAtIndex(_ index: Int) {
248 assert(index >= 0 && index < self.segments.count, "Index at \(index) is out of bounds")
249 self.selectSegment(self.segments[index])
252 func deselectSegment() {
253 if self.indexOfSelectedSegment != NSNotFound {
254 let segment = self.segments[self.indexOfSelectedSegment]
255 segment.setSelected(false)
256 self.indexOfSelectedSegment = NSNotFound
260 // MARK: Drawing Segment Separators
261 override func draw(_ rect: CGRect) {
262 let context = UIGraphicsGetCurrentContext()
263 self.drawSeparatorWithContext(context!)
266 func drawSeparatorWithContext(_ context: CGContext) {
269 if self.segments.count > 1 {
270 let path = CGMutablePath()
272 if self.organiseMode == SegmentOrganiseMode.segmentOrganiseHorizontal {
273 var originX: CGFloat = self.segments[0].frame.size.width + self.separatorWidth/2.0
274 for index in 1..<self.segments.count {
275 path.move(to: CGPoint(x: originX, y: 0.0))
276 path.addLine(to: CGPoint(x: originX, y: frame.size.height))
278 originX += self.segments[index].frame.width + self.separatorWidth
282 var originY: CGFloat = self.segments[0].frame.size.height + self.separatorWidth/2.0
283 for index in 1..<self.segments.count {
284 path.move(to: CGPoint(x: 0.0, y: originY))
285 path.addLine(to: CGPoint(x: frame.size.width, y: originY))
287 originY += self.segments[index].frame.height + self.separatorWidth
291 context.addPath(path)
292 context.setStrokeColor(self.separatorColour.cgColor)
293 context.setLineWidth(self.separatorWidth)
294 context.drawPath(using: CGPathDrawingMode.stroke)
297 context.restoreGState()