How to display only the bottom border for a selected item in a UISegmentedControl?

I am very new to iOS development and have encountered some problems creating an app for the course.

I created a segmented control, and its init function (shown below) is called in the view controller class that contains the segmented control. I was able to remove all the borders and separators of the segmented control from the segmented control class as follows:

import Foundation import UIKit class CashSegmentedControl: UISegmentedControl{ func initUI(){ removeBorders() } func removeBorders(){ self.tintColor = UIColor.clear } 

This is what my result looks like currently

I want it to have a line under each segment. When a segment is selected (similar to instagram)

This is a sample of what I want it to look like

I searched a lot and came across some posts on StackOverflow, but they seem to be for older versions of Swift. I would really appreciate any help in this matter, and if there is a better solution for setting the borders (besides what I did), I would like to know more!

Thanks a lot:)

+10
source share
3 answers

Add the following code to a separate quick file (command + N → New file):

 extension UISegmentedControl{ func removeBorder(){ let backgroundImage = UIImage.getColoredRectImageWith(color: UIColor.white.cgColor, andSize: self.bounds.size) self.setBackgroundImage(backgroundImage, for: .normal, barMetrics: .default) self.setBackgroundImage(backgroundImage, for: .selected, barMetrics: .default) self.setBackgroundImage(backgroundImage, for: .highlighted, barMetrics: .default) let deviderImage = UIImage.getColoredRectImageWith(color: UIColor.white.cgColor, andSize: CGSize(width: 1.0, height: self.bounds.size.height)) self.setDividerImage(deviderImage, forLeftSegmentState: .selected, rightSegmentState: .normal, barMetrics: .default) self.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.gray], for: .normal) self.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor(red: 67/255, green: 129/255, blue: 244/255, alpha: 1.0)], for: .selected) } func addUnderlineForSelectedSegment(){ removeBorder() let underlineWidth: CGFloat = self.bounds.size.width / CGFloat(self.numberOfSegments) let underlineHeight: CGFloat = 2.0 let underlineXPosition = CGFloat(selectedSegmentIndex * Int(underlineWidth)) let underLineYPosition = self.bounds.size.height - 1.0 let underlineFrame = CGRect(x: underlineXPosition, y: underLineYPosition, width: underlineWidth, height: underlineHeight) let underline = UIView(frame: underlineFrame) underline.backgroundColor = UIColor(red: 67/255, green: 129/255, blue: 244/255, alpha: 1.0) underline.tag = 1 self.addSubview(underline) } func changeUnderlinePosition(){ guard let underline = self.viewWithTag(1) else {return} let underlineFinalXPosition = (self.bounds.width / CGFloat(self.numberOfSegments)) * CGFloat(selectedSegmentIndex) UIView.animate(withDuration: 0.1, animations: { underline.frame.origin.x = underlineFinalXPosition }) } } extension UIImage{ class func getColoredRectImageWith(color: CGColor, andSize size: CGSize) -> UIImage{ UIGraphicsBeginImageContextWithOptions(size, false, 0.0) let graphicsContext = UIGraphicsGetCurrentContext() graphicsContext?.setFillColor(color) let rectangle = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height) graphicsContext?.fill(rectangle) let rectangleImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return rectangleImage! } } 

Then after calling segmentedControl.addUnderlineForSelectedSegment() from your viewDidLoad() method and create the @IBAction method for the segmented control, for example:

 @IBAction func segmentedControlDidChange(_ sender: UISegmentedControl){ segmentedControl.changeUnderlinePosition() } 

Then call segmentedControl.changeUnderlinePosition() from this method.

Remember to connect the segmented control from the storyboard to the newly created @IBAction method.

Very important: Remember to use the automatic layout in the storyboard to determine the size and position of your segmented control.

This is the result:

enter image description here

enter image description here

enter image description here

Feel free to ask any other questions you may have :)

+23
source

A.Jam answer in Xcode 9.3, version Swift 4.2

 import UIKit extension UISegmentedControl { func removeBorder(){ let backgroundImage = UIImage.getColoredRectImageWith(color: UIColor.white.cgColor, andSize: self.bounds.size) self.setBackgroundImage(backgroundImage, for: .normal, barMetrics: .default) self.setBackgroundImage(backgroundImage, for: .selected, barMetrics: .default) self.setBackgroundImage(backgroundImage, for: .highlighted, barMetrics: .default) let deviderImage = UIImage.getColoredRectImageWith(color: UIColor.white.cgColor, andSize: CGSize(width: 1.0, height: self.bounds.size.height)) self.setDividerImage(deviderImage, forLeftSegmentState: .selected, rightSegmentState: .normal, barMetrics: .default) self.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor.gray], for: .normal) self.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor(red: 67/255, green: 129/255, blue: 244/255, alpha: 1.0)], for: .selected) } func addUnderlineForSelectedSegment(){ removeBorder() let underlineWidth: CGFloat = self.bounds.size.width / CGFloat(self.numberOfSegments) let underlineHeight: CGFloat = 2.0 let underlineXPosition = CGFloat(selectedSegmentIndex * Int(underlineWidth)) let underLineYPosition = self.bounds.size.height - 1.0 let underlineFrame = CGRect(x: underlineXPosition, y: underLineYPosition, width: underlineWidth, height: underlineHeight) let underline = UIView(frame: underlineFrame) underline.backgroundColor = UIColor(red: 67/255, green: 129/255, blue: 244/255, alpha: 1.0) underline.tag = 1 self.addSubview(underline) } func changeUnderlinePosition(){ guard let underline = self.viewWithTag(1) else {return} let underlineFinalXPosition = (self.bounds.width / CGFloat(self.numberOfSegments)) * CGFloat(selectedSegmentIndex) UIView.animate(withDuration: 0.1, animations: { underline.frame.origin.x = underlineFinalXPosition }) } } extension UIImage { class func getColoredRectImageWith(color: CGColor, andSize size: CGSize) -> UIImage{ UIGraphicsBeginImageContextWithOptions(size, false, 0.0) let graphicsContext = UIGraphicsGetCurrentContext() graphicsContext?.setFillColor(color) let rectangle = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height) graphicsContext?.fill(rectangle) let rectangleImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return rectangleImage! } } 
+4
source

you can use this

 let segmentBottomBorder = CALayer() segmentBottomBorder?.borderColor = UIColor.blue.cgColor segmentBottomBorder?.borderWidth = 3 let x = CGFloat(sender.selectedSegmentIndex) * width let y = sender.frame.size.height - (segmentBottomBorder?.borderWidth)! let width: CGFloat = sender.frame.size.width/3 segmentBottomBorder?.frame = CGRect(x: x, y: y, width: width, height: (segmentBottomBorder?.borderWidth)!) sender.layer.addSublayer(segmentBottomBorder!) 
+1
source

Source: https://habr.com/ru/post/1265365/


All Articles