Last active
April 20, 2016 16:45
-
-
Save Jesse-calkin/b85646f00ab9a32e7e33 to your computer and use it in GitHub Desktop.
An iOS version of the tabs used with Android's view pager, based on a UISegmentedControl
This file contains hidden or 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
| // | |
| // ViewPagerTabs.swift | |
| // | |
| // Created by jesse calkin on 3/14/16. | |
| // Copyright © 2016 Shoshin Boogie. All rights reserved. | |
| // | |
| import UIKit | |
| class ViewPager: UISegmentedControl { | |
| //MARK: - Properties | |
| //MARK: Internal | |
| @IBInspectable var highlightColor: UIColor? | |
| @IBInspectable var activeTextColor: UIColor = UIColor.whiteColor() { | |
| didSet { | |
| setTitleTextAttributes([NSForegroundColorAttributeName: activeTextColor], forState: UIControlState.Selected) | |
| } | |
| } | |
| @IBInspectable var inactiveTextColor: UIColor = UIColor.lightGrayColor() { | |
| didSet { | |
| setTitleTextAttributes([NSForegroundColorAttributeName: inactiveTextColor], forState: UIControlState.Normal) | |
| } | |
| } | |
| @IBInspectable var highlightHeight: CGFloat = 2.0 | |
| @IBInspectable var hightlightInset: CGFloat = 0.0 | |
| var segmentSpacing: CGFloat = 1.0 | |
| override var selectedSegmentIndex: Int { | |
| didSet { | |
| animateSelection() | |
| } | |
| } | |
| //MARK: Private | |
| private let lineLayer = CAShapeLayer() | |
| private var lastPath: CGPath? | |
| //MARK: - View Lifecycle | |
| override init(items: [AnyObject]?) { | |
| super.init(items: items) | |
| setupStyle() | |
| } | |
| required init?(coder aDecoder: NSCoder) { | |
| super.init(coder: aDecoder) | |
| setupStyle() | |
| } | |
| override init(frame: CGRect) { | |
| super.init(frame: frame) | |
| } | |
| override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { | |
| super.touchesEnded(touches, withEvent: event) | |
| animateSelection() | |
| sendActionsForControlEvents(UIControlEvents.TouchUpInside) | |
| } | |
| override func drawRect(rect: CGRect) { | |
| super.drawRect(rect) | |
| animateSelection() | |
| } | |
| override func prepareForInterfaceBuilder() { | |
| super.prepareForInterfaceBuilder() | |
| setupStyle() | |
| animateSelection() | |
| } | |
| //MARK: - Private | |
| private func animateSelection() { | |
| let width = widthForSegmentAtIndex(selectedSegmentIndex) > 0.0 ? widthForSegmentAtIndex(selectedSegmentIndex) : bounds.width / CGFloat(numberOfSegments) | |
| let startPoint = CGPoint(x: width * CGFloat(selectedSegmentIndex) + hightlightInset, y: bounds.maxY - 2) | |
| let endPoint = CGPoint(x: width * CGFloat(selectedSegmentIndex) + (width - hightlightInset), y: bounds.maxY - 2) | |
| let path = UIBezierPath() | |
| path.moveToPoint(startPoint) | |
| path.addLineToPoint(endPoint) | |
| lineLayer.strokeColor = highlightColor?.CGColor ?? tintColor.CGColor | |
| lineLayer.lineWidth = highlightHeight | |
| lineLayer.path = path.CGPath | |
| let lineAnimation = CABasicAnimation(keyPath: "path") | |
| lineAnimation.fromValue = lastPath | |
| lineAnimation.toValue = path.CGPath | |
| lineAnimation.duration = AnimationTime.Default | |
| lineAnimation.fillMode = kCAFillModeForwards | |
| lineAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) | |
| lineLayer.addAnimation(lineAnimation, forKey: "ViewPagerLineAnimation") | |
| lastPath = lineLayer.path | |
| } | |
| private func setupStyle() { | |
| layer.addSublayer(lineLayer) | |
| let colorImage = UIImage.imageWithColor(UIColor.clearColor()) | |
| momentary = false | |
| setDividerImage(colorImage, forLeftSegmentState: UIControlState.Normal, rightSegmentState: UIControlState.Normal, barMetrics: UIBarMetrics.Default) | |
| setBackgroundImage(colorImage, forState: .Normal, barMetrics: .Default) | |
| setBackgroundImage(colorImage, forState: .Selected, barMetrics: .Default) | |
| setBackgroundImage(colorImage, forState: .Highlighted, barMetrics: .Default) | |
| setTitleTextAttributes([NSForegroundColorAttributeName: inactiveTextColor], forState: UIControlState.Normal) | |
| setTitleTextAttributes([NSForegroundColorAttributeName: activeTextColor], forState: UIControlState.Selected) | |
| } | |
| } | |
| //MARK: - UIImage Extension | |
| extension UIImage { | |
| class func imageWithColor(color: UIColor, frame: CGRect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0)) -> UIImage { | |
| UIGraphicsBeginImageContextWithOptions(frame.size, false, 0.0) | |
| let context = UIGraphicsGetCurrentContext() | |
| CGContextSetFillColorWithColor(context, color.CGColor) | |
| CGContextFillRect(context, frame) | |
| let image = UIGraphicsGetImageFromCurrentImageContext() | |
| UIGraphicsEndImageContext() | |
| return image | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment