Skip to content

Instantly share code, notes, and snippets.

@jboullianne
Created July 8, 2019 21:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jboullianne/c9bdd190722a3bd9968015fc5c2e87e5 to your computer and use it in GitHub Desktop.
Save jboullianne/c9bdd190722a3bd9968015fc5c2e87e5 to your computer and use it in GitHub Desktop.
Custom UISegmentedControl with Icons and Animations
//
// STSegmentedView.swift
//
//
// Created by Jean-Marc Boullianne on 6/16/19.
// Copyright © 2019 Jean-Marc Boullianne. All rights reserved.
//
import UIKit
@IBDesignable class STSegmentedView: UIView {
@IBInspectable var selectedBackgroundColor:UIColor = UIColor.blue {
didSet {
self.slideView.backgroundColor = selectedBackgroundColor
}
}
@IBInspectable var selectedTextColor:UIColor = UIColor.white
@IBInspectable var leftButtonText: String = "" {
didSet {
//leftButton.setTitle(self.leftButtonText, for: .normal)
self.buttonTitles[0] = leftButtonText
}
}
@IBInspectable var middleButtonText: String = "" {
didSet {
//middleButton.setTitle(self.middleButtonText, for: .normal)
self.buttonTitles[1] = middleButtonText
}
}
@IBInspectable var rightButtonText: String = "" {
didSet {
//
//rightButton.setTitle(self.rightButtonText, for: .normal)
self.buttonTitles[2] = rightButtonText
}
}
@IBInspectable var leftImage: UIImage = UIImage() {
didSet {
self.buttonImages[0] = leftImage
}
}
@IBInspectable var middleImage: UIImage = UIImage() {
didSet {
self.buttonImages[1] = middleImage
}
}
@IBInspectable var rightImage: UIImage = UIImage() {
didSet {
self.buttonImages[2] = rightImage
}
}
@IBInspectable var leftImageSelected: UIImage = UIImage() {
didSet {
self.buttonSelectImages[0] = leftImageSelected
}
}
@IBInspectable var middleImageSelected: UIImage = UIImage() {
didSet {
self.buttonSelectImages[1] = middleImageSelected
}
}
@IBInspectable var rightImageSelected: UIImage = UIImage() {
didSet {
self.buttonSelectImages[2] = rightImageSelected
}
}
@IBInspectable var startingIndex: Int = 0 {
didSet {
if startingIndex > 2 {
startingIndex = 2
self.didSelectButton(at: startingIndex)
} else if startingIndex < 0 {
startingIndex = 0
self.didSelectButton(at: startingIndex)
} else {
self.didSelectButton(at: startingIndex)
}
}
}
lazy var leftButton: UIButton = {
let button = UIButton(type: .custom)
button.setTitle("", for: .normal)
button.titleLabel?.font = UIFont(name: "HelveticaNeue-Bold", size: 14)
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0)
return button
}()
lazy var middleButton: UIButton = {
let button = UIButton(type: .custom)
button.setTitle("", for: .normal)
button.titleLabel?.font = UIFont(name: "HelveticaNeue-Bold", size: 14)
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0)
return button
}()
lazy var rightButton: UIButton = {
let button = UIButton(type: .custom)
button.setTitle("", for: .normal)
button.titleLabel?.font = UIFont(name: "HelveticaNeue-Bold", size: 14)
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0)
return button
}()
lazy var stackView: UIStackView = UIStackView(arrangedSubviews: [])
lazy var slideView: UIView = {
var view = UIView(frame: CGRect.zero)
view.backgroundColor = self.selectedBackgroundColor
return view
}()
private var currentIndex: Int = 0
private var buttons: [UIButton] = []
private lazy var buttonTitles:[String] = [leftButtonText, middleButtonText, rightButtonText]
private lazy var buttonImages:[UIImage] = [leftImage, middleImage, rightImage]
private lazy var buttonSelectImages:[UIImage] = [leftImageSelected, middleImageSelected, rightImageSelected]
var delegate: STSegmentedViewDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
private func setupView() {
self.buttons = [leftButton, middleButton, rightButton]
self.buttonTitles = [leftButtonText, middleButtonText, rightButtonText]
self.buttonImages = [leftImage, middleImage, rightImage]
self.buttonSelectImages = [leftImageSelected, middleImageSelected, rightImageSelected]
leftButton.sizeToFit()
middleButton.sizeToFit()
rightButton.sizeToFit()
stackView.addArrangedSubview(leftButton)
stackView.addArrangedSubview(middleButton)
stackView.addArrangedSubview(rightButton)
stackView.axis = .horizontal
stackView.distribution = .fillProportionally
stackView.alignment = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(slideView)
self.addSubview(stackView)
stackView.pinEdges(to: self)
leftButton.addTarget(self, action: #selector(STSegmentedView.buttonTapped(sender:)), for: .touchUpInside)
middleButton.addTarget(self, action: #selector(STSegmentedView.buttonTapped(sender:)), for: .touchUpInside)
rightButton.addTarget(self, action: #selector(STSegmentedView.buttonTapped(sender:)), for: .touchUpInside)
leftButton.setTitle("", for: .normal)
middleButton.setTitle("", for: .normal)
rightButton.setTitle("", for: .normal)
//setupFirstSelection()
}
override func layoutSubviews() {
super.layoutSubviews()
leftButton.setImage(buttonImages[0], for: .normal)
middleButton.setImage(buttonImages[1], for: .normal)
rightButton.setImage(buttonImages[2], for: .normal)
self.setupFirstSelection()
}
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
@objc func buttonTapped(sender :UIButton!) {
switch sender {
case leftButton:
didSelectButton(at: 0)
break
case middleButton:
didSelectButton(at: 1)
break
case rightButton:
didSelectButton(at: 2)
break
default:
break
}
}
func didSelectButton(at index: Int) {
//if self.currentIndex == index { return }
self.delegate?.didSelectPage(index: index)
let oldButton = self.buttons[self.currentIndex]
//oldButton.backgroundColor = UIColor.clear
let newButton = self.buttons[index]
//newButton.backgroundColor = self.selectedBackgroundColor
newButton.alpha = 0.0
oldButton.setImage(self.buttonImages[self.currentIndex], for: .normal)
newButton.setImage(self.buttonSelectImages[index], for: .normal)
UIView.animate(withDuration: 0.1) {
oldButton.setTitle("", for: .normal)
newButton.setTitle(self.buttonTitles[index], for: .normal)
self.stackView.layoutSubviews()
self.layoutIfNeeded()
newButton.alpha = 1.0
}
UIView.animate(withDuration: 0.2, delay: 0, options: [], animations: {
self.slideView.frame = newButton.frame
self.layoutIfNeeded()
}, completion: nil)
self.currentIndex = index
}
func setupFirstSelection() {
let index = self.startingIndex
let newButton = self.buttons[index]
newButton.setTitle(self.buttonTitles[index], for: .normal)
newButton.setImage(self.buttonSelectImages[index], for: .normal)
self.stackView.layoutSubviews()
self.slideView.frame = newButton.frame
self.slideView.layer.cornerRadius = self.slideView.frame.height/2.0
self.currentIndex = index
}
}
extension UIView {
func pinEdges(to other: UIView) {
leadingAnchor.constraint(equalTo: other.leadingAnchor).isActive = true
trailingAnchor.constraint(equalTo: other.trailingAnchor).isActive = true
topAnchor.constraint(equalTo: other.topAnchor).isActive = true
bottomAnchor.constraint(equalTo: other.bottomAnchor).isActive = true
}
}
protocol STSegmentedViewDelegate {
func didSelectPage(index: Int)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment