I wanna use a thick line at the bottom of a UITabbarItems as a selection indicator. Due to the fact that the App must work on different phone sizes, I cannot use a image as selection indicator. That's why I think I have to use Swift to do this. (The line has to be 1/3 of page width).
I tried to use UITabBarItem.appearance()
but without success.
You can do it with add custom image, that will be created in your code, to selectionIndicatorImage
on your UITabBar
object. For example you can create extension
for UIImage
class like this:
extension UIImage {
func createSelectionIndicator(color: UIColor, size: CGSize, lineWidth: CGFloat) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(CGRectMake(0, size.height - lineWidth, size.width, lineWidth))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
And call it in your first loaded ViewController
like this:
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let tabBar = self.tabBarController!.tabBar
tabBar.selectionIndicatorImage = UIImage().createSelectionIndicator(UIColor.blueColor(), size: CGSizeMake(tabBar.frame.width/CGFloat(tabBar.items!.count), tabBar.frame.height), lineWidth: 2.0)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
In this case result will be like this:
Swift 3:
extension UIImage {
func createSelectionIndicator(color: UIColor, size: CGSize, lineHeight: CGFloat) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(CGRect(origin: CGPoint(x: 0,y :size.height - lineHeight), size: CGSize(width: size.width, height: lineHeight)))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
override func viewDidLoad() {
super.viewDidLoad()
let tabBar = self.tabBarController!.tabBar
tabBar.selectionIndicatorImage = UIImage().createSelectionIndicator(color: UIColor.blue, size: CGSize(width: tabBar.frame.width/CGFloat(tabBar.items!.count), height: tabBar.frame.height), lineHeight: 2.0)
}
Swift 4.x
Xcode 10.x
extension UIImage {
func createSelectionIndicator(color: UIColor, size: CGSize, lineWidth: CGFloat) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(CGRect(x: 0, y: size.height - lineWidth, width: size.width, height: lineWidth))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
Use
tabBar.selectionIndicatorImage = UIImage().createSelectionIndicator(color: BLUE, size: CGSize(width: tabBar.frame.width/CGFloat(tabBar.items!.count), height: tabBar.frame.height), lineWidth: 2.0)
I solved my problem.
Features of this tiny code snippet:
- width is dynamic
- it is animated
it is a lot more customizable for future features
class FirstViewController: UIViewController {
let rectShape = CAShapeLayer()
let indicatorHeight: CGFloat = 5
var indicatorWidth: CGFloat!
let indicatorBottomMargin: CGFloat = 2
let indicatorLeftMargin: CGFloat = 2
override func viewDidLoad() {
super.viewDidLoad()
// setup tabbar indicator
rectShape.fillColor = UIColor.redColor().CGColor
indicatorWidth = view.bounds.maxX / 2 // count of items
self.tabBarController!.view.layer.addSublayer(rectShape)
self.tabBarController?.delegate = self
// initial position
updateTabbarIndicatorBySelectedTabIndex(0)
}
func updateTabbarIndicatorBySelectedTabIndex(index: Int) -> Void
{
let updatedBounds = CGRect( x: CGFloat(index) * (indicatorWidth + indicatorLeftMargin),
y: view.bounds.maxY - indicatorHeight,
width: indicatorWidth - indicatorLeftMargin,
height: indicatorHeight)
let path = CGPathCreateMutable()
CGPathAddRect(path, nil, updatedBounds)
rectShape.path = path
}
}
extension FirstViewController: UITabBarControllerDelegate {
func tabBarController(tabBarController: UITabBarController, didSelectViewController viewController: UIViewController) {
updateTabbarIndicatorBySelectedTabIndex(tabBarController.selectedIndex)
}
}