Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 52 additions & 45 deletions Pod/Classes/XMSegmentedControl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,58 +44,67 @@ public class XMSegmentedControl: UIView {

public var delegate: XMSegmentedControlDelegate?
private var highlightView: UIView!

/**
Defines the height of the highlighted edge if `selectedItemHighlightStyle` is either `TopEdge` or `BottomEdge`
- Note: Changes only take place if `selectedItemHighlightStyle` is either `TopEdge` or `BottomEdge`
*/
public var edgeHighlightHeight: CGFloat = 5.0

/// Changes the background of the selected segment.
@IBInspectable public var highlightColor = UIColor(red: 42/255, green: 132/255, blue: 210/255, alpha: 1) {
didSet {
self.update()
}
}

/// Changes the font color or the icon tint color for the segments.
@IBInspectable public var tint = UIColor.whiteColor() {
didSet {
self.update()
}
}

/// Changes the font color or the icon tint for the selected segment.
@IBInspectable public var highlightTint = UIColor.whiteColor() {
didSet {
self.update()
}
}

/**
Sets the segmented control content type to `Text` and uses the content of the array to create the segments.
- Note: Only six elements will be displayed.
*/
public var segmentTitle: [String] = []{
public var segmentTitle: [String] = [] {
didSet {
segmentTitle = segmentTitle.count > 6 ? Array(segmentTitle[0..<6]) : segmentTitle
contentType = .Text
self.update()
}
}

/**
Sets the segmented control content type to `Icon` and uses the content of the array to create the segments.
- Note: Only six elements will be displayed.
*/
public var segmentIcon: [UIImage] = []{
public var segmentIcon: [UIImage] = [] {
didSet {
segmentIcon = segmentIcon.count > 6 ? Array(segmentIcon[0..<6]) : segmentIcon
contentType = .Icon
self.update()
}
}


/**
Sets the image insets for icons.
*/
public var iconInsets: CGFloat = 12 {
didSet {
self.update()
}
}

/**
Sets the segmented control content type to `Hybrid` (i.e. displaying icons and text) and uses the content of the tuple to create the segments.
- Note: Only six elements will be displayed.
Expand Down Expand Up @@ -125,44 +134,44 @@ public class XMSegmentedControl: UIView {
self.update()
}
}


/// The segment index of the selected item.
public var selectedSegment: Int = 0

/**
Sets the font for the text displayed in the segmented control if `contentType` is `Text`
- Note: Changes only take place if `contentType` is `Text`
*/
public var font = UIFont(name: "AvenirNext-DemiBold", size: 15)!

/// Sets the segmented control selected item highlight style to `Background`, `TopEdge` or `BottomEdge`.
public var selectedItemHighlightStyle: XMSelectedItemHighlightStyle = .Background

/// Sets the segmented control content type to `Text` or `Icon`
public var contentType: XMContentType = .Text

/// Initializes and returns a newly allocated XMSegmentedControl object with the specified frame rectangle. It sets the segments of the control from the given `segmentTitle` array and the highlight style for the selected item.
public init (frame: CGRect, segmentTitle: [String], selectedItemHighlightStyle: XMSelectedItemHighlightStyle) {
super.init (frame: frame)

self.commonInit(segmentTitle, highlightStyle: selectedItemHighlightStyle)
}

/// Initializes and returns a newly allocated XMSegmentedControl object with the specified frame rectangle. It sets the segments of the control from the given `segmentIcon` array and the highlight style for the selected item.
public init (frame: CGRect, segmentIcon: [UIImage], selectedItemHighlightStyle: XMSelectedItemHighlightStyle) {
super.init (frame: frame)

self.commonInit(segmentIcon, highlightStyle: selectedItemHighlightStyle)
}

/// Initializes and returns a newly allocated XMSegmentedControl object with the specified frame rectangle. It sets the segments of the control from the given `segmentContent` tuple and the highlight style for the selected item. Notice that the tuple consists of an array containing the titles and another array containing the icons. The two arrays must be the same size.
public init (frame: CGRect, segmentContent: ([String], [UIImage]), selectedItemHighlightStyle: XMSelectedItemHighlightStyle) {
super.init (frame: frame)

self.commonInit(segmentContent, highlightStyle: selectedItemHighlightStyle)
}

/// Common initializer.
private func commonInit(data: Any, highlightStyle: XMSelectedItemHighlightStyle) {
if let segmentTitle = data as? [String] {
Expand All @@ -176,40 +185,40 @@ public class XMSegmentedControl: UIView {
backgroundColor = UIColor(red: 45/255, green: 62/255, blue: 100/255, alpha: 1)
selectedItemHighlightStyle = highlightStyle
}

public override init(frame: CGRect) {
super.init(frame: frame)

backgroundColor = UIColor(red: 45/255, green: 62/255, blue: 100/255, alpha: 1)
}

required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)

backgroundColor = UIColor(red: 45/255, green: 62/255, blue: 100/255, alpha: 1)
}

/// Prepares the render of the view for the Storyboard.
override public func prepareForInterfaceBuilder() {
segmentTitle = ["Only", "For", "Show"]
backgroundColor = UIColor(red: 45/255, green: 62/255, blue: 100/255, alpha: 1)
}

override public func layoutSubviews() {
self.update()
}

/// Forces the segmented control to reload.
public func update() {
func addSegments(startingPosition starting: CGFloat, sections: Int, width: CGFloat, height: CGFloat) {
for (var i = 0; i < sections; i++) {
for i in 0 ..< sections {
let frame = CGRect(x: starting + (CGFloat(i) * width), y: 0, width: width, height: height)
let tab = UIButton(type: UIButtonType.System)
tab.frame = frame

switch contentType {
case .Icon:
tab.imageEdgeInsets = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12)
tab.imageEdgeInsets = UIEdgeInsets(top: iconInsets, left: iconInsets, bottom: iconInsets, right: iconInsets)
tab.imageView?.contentMode = UIViewContentMode.ScaleAspectFit
tab.tintColor = i == selectedSegment ? highlightTint : tint
tab.setImage(segmentIcon[i], forState: .Normal)
Expand All @@ -228,15 +237,15 @@ public class XMSegmentedControl: UIView {
tab.titleLabel?.font = font
tab.imageView?.contentMode = .ScaleAspectFit
tab.tintColor = i == selectedSegment ? highlightTint : tint

}

tab.tag = i
tab.addTarget(self, action: "segmentPressed:", forControlEvents: .TouchUpInside)
tab.addTarget(self, action: #selector(XMSegmentedControl.segmentPressed(_:)), forControlEvents: .TouchUpInside)
self.addSubview(tab)
}
}

func addHighlightView(startingPosition starting: CGFloat, width: CGFloat) {
switch selectedItemHighlightStyle {
case .Background:
Expand All @@ -250,7 +259,7 @@ public class XMSegmentedControl: UIView {
highlightView.backgroundColor = highlightColor
self.addSubview(highlightView)
}

(subviews as [UIView]).forEach { $0.removeFromSuperview() }
let totalWidth = frame.width

Expand All @@ -266,19 +275,17 @@ public class XMSegmentedControl: UIView {
addSegments(startingPosition: 0, sections: tabBarSections, width: sectionWidth, height: frame.height)
} else if contentType == .Icon {
let tabBarSections = segmentIcon.count
let sectionWidth = totalWidth / 6
let availableSpace = totalWidth - (sectionWidth * CGFloat(6 - tabBarSections))
let startingXPosition = (totalWidth - availableSpace) / 2
addHighlightView(startingPosition: startingXPosition + (sectionWidth * CGFloat(selectedSegment)), width: sectionWidth)
addSegments(startingPosition: startingXPosition, sections: tabBarSections, width: sectionWidth, height: frame.height)
let sectionWidth = totalWidth / CGFloat(tabBarSections)
addHighlightView(startingPosition: CGFloat(selectedSegment) * sectionWidth, width: sectionWidth)
addSegments(startingPosition: 0, sections: tabBarSections, width: sectionWidth, height: frame.height)
} else { // Hybrid
let tabBarSections = segmentContent.text.count
let sectionWidth = totalWidth / CGFloat(tabBarSections)
addHighlightView(startingPosition: CGFloat(selectedSegment) * sectionWidth, width: sectionWidth)
addSegments(startingPosition: 0, sections: tabBarSections, width: sectionWidth, height: frame.height)
}
}

/// Called whenever a segment is pressed. Sends the information to the delegate.
@objc private func segmentPressed(sender: UIButton) {
func isUIButton(view: UIView) -> Bool {
Expand All @@ -287,10 +294,10 @@ public class XMSegmentedControl: UIView {

let xPosition = sender.frame.origin.x
let newPosition = CGPoint(x: xPosition, y: highlightView.frame.origin.y)

UIView.animateWithDuration(0.3, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.7, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.highlightView.frame.origin = newPosition

switch(self.contentType) {
case .Icon, .Hybrid:
((self.subviews.filter(isUIButton)) as! [UIButton]).forEach { $0.tintColor = self.tint }
Expand All @@ -299,13 +306,13 @@ public class XMSegmentedControl: UIView {
((self.subviews.filter(isUIButton)) as! [UIButton]).forEach { $0.setTitleColor(self.tint, forState: .Normal) }
sender.setTitleColor(self.highlightTint, forState: .Normal)
}

}, completion: nil)

selectedSegment = sender.tag
delegate?.xmSegmentedControl(self, selectedSegment: selectedSegment)
}

/// Press indexed tab
public func pressTabWithIndex(index: Int) {
for subview in self.subviews where subview.tag == index {
Expand All @@ -315,14 +322,14 @@ public class XMSegmentedControl: UIView {
}
}
}

/// Scales an Image to the size provided. It takes into account alpha. And it uses the screen's scale to resize.
private func resizeImage(image: UIImage) -> UIImage {
let size = CGSize(width: 20, height: 20)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
image.drawInRect(CGRect(origin: CGPointZero, size: size))
image.drawInRect(CGRect(origin: CGPoint.zero, size: size))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return scaledImage
}
}
}