Skip to content

Instantly share code, notes, and snippets.

@KalpeshTalkar
Last active July 17, 2018 10:27
Show Gist options
  • Save KalpeshTalkar/4ad780fabf59c1527a5a894e16331735 to your computer and use it in GitHub Desktop.
Save KalpeshTalkar/4ad780fabf59c1527a5a894e16331735 to your computer and use it in GitHub Desktop.
IBDesignable tab bar view written in Swift 3
//
// Copyright © 2017 Kalpesh Talkar. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// For support: https://gist.github.com/KalpeshTalkar/4ad780fabf59c1527a5a894e16331735
//
import UIKit
protocol KTabBarDelegate {
func didSelectTabItem(tabBar: KTabBar, at index:Int)
}
@IBDesignable
class KTabBar: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
// MARK: - IBInspectables
@IBInspectable var quickSetup: Bool = false {
didSet {
setUpCollectionView()
}
}
@IBInspectable var items: String = "Item 1;Item 2" {
didSet {
quickItems = items.components(separatedBy: ";")
setUpCollectionView()
}
}
@IBInspectable var selectedIndex: Int = 0 {
didSet {
setUpCollectionView()
}
}
@IBInspectable var selectionIndicatorColor: UIColor = UIColor.white {
didSet {
setUpCollectionView()
}
}
@IBInspectable var selectedItemColor: UIColor = UIColor.darkGray {
didSet {
setUpCollectionView()
}
}
@IBInspectable var itemColor: UIColor = UIColor.gray {
didSet {
setUpCollectionView()
}
}
@IBInspectable var textColor: UIColor = UIColor.white {
didSet {
setUpCollectionView()
}
}
@IBInspectable var minTabBarItemWidth: CGFloat = 80 {
didSet {
setUpCollectionView()
}
}
var totalTabs: Int {
get {
return quickItems.count
}
}
// MARK: - variables
var delegate: KTabBarDelegate?
private var collectionView: UICollectionView?
private var quickItems = [String]()
//private var items = [String]()
// MARK: - init methods
#if !TARGET_INTERFACE_BUILDER
override init(frame: CGRect) {
super.init(frame: frame)
setUpCollectionView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setUpCollectionView()
}
override func layoutSubviews() {
super.layoutSubviews()
if nil != collectionView {
collectionView!.frame = bounds
collectionView!.layoutSubviews()
}
}
#endif
// MARK: - UICollectionView Setup
private func setUpCollectionView() {
if nil == collectionView {
// UICollectionViewLayout
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
// UICollectionView
collectionView = UICollectionView(frame: bounds, collectionViewLayout: layout)
collectionView!.backgroundColor = UIColor.clear
collectionView?.showsHorizontalScrollIndicator = false
collectionView!.dataSource = self
collectionView!.delegate = self
collectionView!.register(UINib.init(nibName: String.className(KTabBarCell.self), bundle: nil), forCellWithReuseIdentifier: String.className(KTabBarCell.self))
collectionView!.backgroundColor = UIColor.white
}
collectionView!.removeFromSuperview()
addSubview(collectionView!)
collectionView!.reloadData()
}
// MARK: - UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return quickItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String.className(KTabBarCell.self), for: indexPath) as! KTabBarCell
let isSelected = selectedIndex == indexPath.row
if isSelected {
cell.backgroundColor = selectedItemColor
cell.selectionIndicator.backgroundColor = selectionIndicatorColor
} else {
cell.backgroundColor = itemColor
cell.selectionIndicator.backgroundColor = UIColor.clear
}
cell.itemLabel.textColor = textColor
cell.itemLabel.text = quickItems[indexPath.item]
return cell
}
// MARK: - UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndex = indexPath.item
collectionView.reloadItems(at: collectionView.indexPathsForVisibleItems)
collectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.centeredHorizontally, animated: true)
if nil != delegate {
delegate!.didSelectTabItem(tabBar: self, at: selectedIndex)
}
}
// MARK: - UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 16)
label.text = quickItems[indexPath.item]
let constrainedSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: KTabBarCell.ItemLabelHeight)
let requiredSize = label.sizeThatFits(constrainedSize)
var width = requiredSize.width+KTabBarCell.LeftRightMargin
if width < minTabBarItemWidth {
width = minTabBarItemWidth
}
return CGSize(width: width, height: collectionView.frame.height)
}
// MARK: - Helper methods
func selectTabItem(at index: Int) {
let indexPath = IndexPath(item: index, section: 0)
selectedIndex = indexPath.item
collectionView!.reloadItems(at: collectionView!.indexPathsForVisibleItems)
collectionView!.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.centeredHorizontally, animated: true)
}
}
//
// Copyright © 2017 Kalpesh Talkar. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// For support: https://gist.github.com/KalpeshTalkar/4ad780fabf59c1527a5a894e16331735
//
import UIKit
class KTabBarCell: UICollectionViewCell {
static let ItemLabelHeight: CGFloat = 20
static let LeftRightMargin: CGFloat = 16
@IBOutlet weak var selectionIndicator: UIView!
@IBOutlet weak var itemLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11201" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="KTabBarCell" customModule="EduGuru" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="48" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="48" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="T2n-ni-Chu">
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="5" id="asK-Cm-Ei3"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Item" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4qv-7C-8p7">
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</view>
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="T2n-ni-Chu" firstAttribute="top" secondItem="4qv-7C-8p7" secondAttribute="bottom" constant="8" id="9MZ-p8-d66"/>
<constraint firstItem="4qv-7C-8p7" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="11" id="K87-yd-SEI"/>
<constraint firstAttribute="trailing" secondItem="T2n-ni-Chu" secondAttribute="trailing" id="PDx-EW-wPc"/>
<constraint firstItem="4qv-7C-8p7" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="8" id="Qee-SX-Ew2"/>
<constraint firstAttribute="bottom" secondItem="T2n-ni-Chu" secondAttribute="bottom" id="acB-4D-L3W"/>
<constraint firstItem="T2n-ni-Chu" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="lVO-p8-TvD"/>
<constraint firstAttribute="trailing" secondItem="4qv-7C-8p7" secondAttribute="trailing" constant="8" id="x7j-mX-1eW"/>
</constraints>
<connections>
<outlet property="itemLabel" destination="4qv-7C-8p7" id="rGm-aP-aID"/>
<outlet property="selectionIndicator" destination="T2n-ni-Chu" id="hjX-ef-cPc"/>
</connections>
<point key="canvasLocation" x="-260" y="-118"/>
</collectionViewCell>
</objects>
</document>
@KalpeshTalkar
Copy link
Author

KalpeshTalkar commented Apr 18, 2017

Usage:
Using Interface Builder/Storyboard

Drag a UIView and set its class to KTabBar
In the attribute inspector, you can set the attributes as per your requirements.
In the items text box, you can set your tab bar items separated by semi-colon (;)
e.g. : "Item1;Item2;Item3"

IBInspectable attributes:

  • items
  • selectedIndex
  • itemColor
  • selectedItemColor
  • selectionIndicatorColor
  • textColor
  • minTabBarItemWidth
    Other properties:
  • totalTabs: returns the count of all tabs in the tab bar
    Other methods
  • func selectTabItem(at index: Int) : Select tab bar item at the specified index
    Delegate methods
  • func didSelectTabItem(tabBar: KTabBar, at index:Int) : called when tab bar item is selected

Programmatically

  • Using the property items:

items is a IBInspectable String. You can set your tab bar items from the interface builder.
To use this using interface builder, you can set multiple tab bar items separated by semi colon (;)
e.g. : "Item1;Item2;Item3"
let tabBar = KTabBar(frame: CGRect(x: 0, y: 64, width: self.view.bounds.width, height: 44))
tabBar.items = "Item1;Item2;Item3"
tabBar.minTabBarItemWidth = 150
tabBar.delegate = self
self.view.addSubview(tabBar)

  • Using the property quickItems:

quickItems is a string array which takes the tab bar item titles
let tabBar = KTabBar(frame: CGRect(x: 0, y: 64, width: self.view.bounds.width, height: 44))
tabBar.quickItems = ["Item1","Item2","Item3"]
tabBar.minTabBarItemWidth = 150
tabBar.delegate = self
self.view.addSubview(tabBar)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment