// // SMSegmentView.swift // // Created by Si MA on 03/01/2015. // Copyright (c) 2015 Si Ma. All rights reserved. // import UIKit /* Keys for segment properties */ // This is mainly for the top/bottom margin of the imageView let keyContentVerticalMargin = "VerticalMargin" // The colour when the segment is under selected/unselected let keySegmentOnSelectionColour = "OnSelectionBackgroundColour" let keySegmentOffSelectionColour = "OffSelectionBackgroundColour" // The colour of the text in the segment for the segment is under selected/unselected let keySegmentOnSelectionTextColour = "OnSelectionTextColour" let keySegmentOffSelectionTextColour = "OffSelectionTextColour" // The font of the text in the segment let keySegmentTitleFont = "TitleFont" enum SegmentOrganiseMode: Int { case segmentOrganiseHorizontal = 0 case segmentOrganiseVertical } protocol SMSegmentViewDelegate: class { func segmentView(_ segmentView: SMSegmentView, didSelectSegmentAtIndex index: Int) } class SMSegmentView: UIView, SMSegmentDelegate { weak var delegate: SMSegmentViewDelegate? var indexOfSelectedSegment = NSNotFound var numberOfSegments = 0 var organiseMode: SegmentOrganiseMode = SegmentOrganiseMode.segmentOrganiseHorizontal { didSet { self.setNeedsDisplay() } } var segmentVerticalMargin: CGFloat = 5.0 { didSet { for segment in self.segments { segment.verticalMargin = self.segmentVerticalMargin } } } // Segment Separator var separatorColour: UIColor = UIColor.lightGray { didSet { self.setNeedsDisplay() } } var separatorWidth: CGFloat = 1.0 { didSet { for segment in self.segments { segment.separatorWidth = self.separatorWidth } self.updateFrameForSegments() } } // Segment Colour var segmentOnSelectionColour: UIColor = UIColor.darkGray { didSet { for segment in self.segments { segment.onSelectionColour = self.segmentOnSelectionColour } } } var segmentOffSelectionColour: UIColor = UIColor.white { didSet { for segment in self.segments { segment.offSelectionColour = self.segmentOffSelectionColour } } } // Segment Title Text Colour & Font var segmentOnSelectionTextColour: UIColor = UIColor.white { didSet { for segment in self.segments { segment.onSelectionTextColour = self.segmentOnSelectionTextColour } } } var segmentOffSelectionTextColour: UIColor = UIColor.darkGray { didSet { for segment in self.segments { segment.offSelectionTextColour = self.segmentOffSelectionTextColour } } } var segmentTitleFont: UIFont = UIFont.systemFont(ofSize: 17.0) { didSet { for segment in self.segments { segment.titleFont = self.segmentTitleFont } } } override var frame: CGRect { didSet { self.updateFrameForSegments() } } var segments: Array = Array() required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override init(frame: CGRect) { super.init(frame: frame) self.backgroundColor = UIColor.clear self.layer.masksToBounds = true } init(frame: CGRect, separatorColour: UIColor, separatorWidth: CGFloat, segmentProperties: Dictionary?) { self.separatorColour = separatorColour self.separatorWidth = separatorWidth if let margin = segmentProperties?[keyContentVerticalMargin] as? Float { self.segmentVerticalMargin = CGFloat(margin) } if let onSelectionColour = segmentProperties?[keySegmentOnSelectionColour] as? UIColor { self.segmentOnSelectionColour = onSelectionColour } else { self.segmentOnSelectionColour = UIColor.darkGray } if let offSelectionColour = segmentProperties?[keySegmentOffSelectionColour] as? UIColor { self.segmentOffSelectionColour = offSelectionColour } else { self.segmentOffSelectionColour = UIColor.white } if let onSelectionTextColour = segmentProperties?[keySegmentOnSelectionTextColour] as? UIColor { self.segmentOnSelectionTextColour = onSelectionTextColour } else { self.segmentOnSelectionTextColour = UIColor.white } if let offSelectionTextColour = segmentProperties?[keySegmentOffSelectionTextColour] as? UIColor { self.segmentOffSelectionTextColour = offSelectionTextColour } else { self.segmentOffSelectionTextColour = UIColor.darkGray } if let titleFont = segmentProperties?[keySegmentTitleFont] as? UIFont { self.segmentTitleFont = titleFont } else { self.segmentTitleFont = UIFont.systemFont(ofSize: 17.0) } super.init(frame: frame) self.backgroundColor = UIColor.clear self.layer.masksToBounds = true } func addSegmentWithTitle(_ title: String?, onSelectionImage: UIImage?, offSelectionImage: UIImage?) { let segment = SMSegment( separatorWidth: self.separatorWidth, verticalMargin: self.segmentVerticalMargin, onSelectionColour: self.segmentOnSelectionColour, offSelectionColour: self.segmentOffSelectionColour, onSelectionTextColour: self.segmentOnSelectionTextColour, offSelectionTextColour: self.segmentOffSelectionTextColour, titleFont: self.segmentTitleFont ) segment.index = self.segments.count self.segments.append(segment) self.updateFrameForSegments() segment.delegate = self segment.title = title segment.onSelectionImage = onSelectionImage segment.offSelectionImage = offSelectionImage self.addSubview(segment) self.numberOfSegments = self.segments.count } func updateFrameForSegments() { if self.segments.count == 0 { return } let count = self.segments.count if count > 1 { if self.organiseMode == SegmentOrganiseMode.segmentOrganiseHorizontal { let segmentWidth = (self.frame.size.width - self.separatorWidth*CGFloat(count-1)) / CGFloat(count) var originX: CGFloat = 0.0 for segment in self.segments { segment.frame = CGRect(x: originX, y: 0.0, width: segmentWidth, height: self.frame.size.height) originX += segmentWidth + self.separatorWidth } } else { let segmentHeight = (self.frame.size.height - self.separatorWidth*CGFloat(count-1)) / CGFloat(count) var originY: CGFloat = 0.0 for segment in self.segments { segment.frame = CGRect(x: 0.0, y: originY, width: self.frame.size.width, height: segmentHeight) originY += segmentHeight + self.separatorWidth } } } else { self.segments[0].frame = CGRect(x: 0.0, y: 0.0, width: self.frame.size.width, height: self.frame.size.height) } self.setNeedsDisplay() } // MARK: SMSegment Delegate func selectSegment(_ segment: SMSegment) { if self.indexOfSelectedSegment != NSNotFound { let previousSelectedSegment = self.segments[self.indexOfSelectedSegment] previousSelectedSegment.setSelected(false) } self.indexOfSelectedSegment = segment.index segment.setSelected(true) self.delegate?.segmentView(self, didSelectSegmentAtIndex: segment.index) } // MARK: Actions func selectSegmentAtIndex(_ index: Int) { assert(index >= 0 && index < self.segments.count, "Index at \(index) is out of bounds") self.selectSegment(self.segments[index]) } func deselectSegment() { if self.indexOfSelectedSegment != NSNotFound { let segment = self.segments[self.indexOfSelectedSegment] segment.setSelected(false) self.indexOfSelectedSegment = NSNotFound } } // MARK: Drawing Segment Separators override func draw(_ rect: CGRect) { let context = UIGraphicsGetCurrentContext() self.drawSeparatorWithContext(context!) } func drawSeparatorWithContext(_ context: CGContext) { context.saveGState() if self.segments.count > 1 { let path = CGMutablePath() if self.organiseMode == SegmentOrganiseMode.segmentOrganiseHorizontal { var originX: CGFloat = self.segments[0].frame.size.width + self.separatorWidth/2.0 for index in 1..