Je suis extrêmement nouveau dans le développement iOS et j'ai rencontré des problèmes lors de la création d'une application pour un cours.
J'ai créé un contrôle segmenté et sa fonction init (illustrée ci-dessous) est appelée dans la classe de contrôleur de vue contenant le contrôle segmenté. J'ai pu supprimer toutes les bordures et séparateurs du contrôle segmenté de la classe de contrôle segmenté comme suit:
import Foundation
import UIKit
class CashSegmentedControl: UISegmentedControl{
func initUI(){
removeBorders()
}
func removeBorders(){
self.tintColor = UIColor.clear
}
Je veux qu'il y ait une ligne sous chaque segment QUAND le segment est sélectionné (similaire à instagram)
J'ai beaucoup cherché et je suis tombé sur certains messages sur StackOverflow, mais ils semblent concerner des versions plus anciennes de Swift. J'apprécierais vraiment toute aide à ce sujet, et s'il existe une meilleure solution pour personnaliser les bordures (autre que ce que j'ai fait), j'aimerais en savoir plus!
Merci beaucoup :)
Ajoutez le code suivant dans un fichier Swift (commande + N -> Nouveau fichier) séparé):
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!
}
}
Ensuite, après avoir appelé segmentedControl.addUnderlineForSelectedSegment()
à partir de votre méthode viewDidLoad()
, et créez une méthode @IBAction
Pour le contrôle segmenté comme suit:
@IBAction func segmentedControlDidChange(_ sender: UISegmentedControl){
segmentedControl.changeUnderlinePosition()
}
Appelez ensuite segmentedControl.changeUnderlinePosition()
depuis cette méthode.
N'oubliez pas de connecter le contrôle segmenté de votre storyboard à la méthode @IBAction
Que vous venez de créer.
Très important : N'oubliez pas d'utiliser la disposition automatique dans le storyboard pour déterminer la taille et la position de votre contrôle segmenté.
Voici le résultat:
N'hésitez pas à poser toutes les autres questions que vous pourriez avoir :)
Réponse de A.Jam dans Xcode 9.3, Swift version 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!
}
}
Réponse de A.Jam dans Xcode 10.1, Swift 4.2 version - sans extension UIImage
et un soulignement gris pour tous les segments
extension UISegmentedControl {
func removeBorder(){
self.tintColor = UIColor.clear
self.backgroundColor = UIColor.clear
self.setTitleTextAttributes( [NSAttributedString.Key.foregroundColor : UIColor.orange], for: .selected)
self.setTitleTextAttributes( [NSAttributedString.Key.foregroundColor : UIColor.gray], for: .normal)
}
func setupSegment() {
self.removeBorder()
let segmentUnderlineWidth: CGFloat = self.bounds.width
let segmentUnderlineHeight: CGFloat = 2.0
let segmentUnderlineXPosition = self.bounds.minX
let segmentUnderLineYPosition = self.bounds.size.height - 1.0
let segmentUnderlineFrame = CGRect(x: segmentUnderlineXPosition, y: segmentUnderLineYPosition, width: segmentUnderlineWidth, height: segmentUnderlineHeight)
let segmentUnderline = UIView(frame: segmentUnderlineFrame)
segmentUnderline.backgroundColor = UIColor.gray
self.addSubview(segmentUnderline)
self.addUnderlineForSelectedSegment()
}
func addUnderlineForSelectedSegment(){
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.orange
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)
underline.frame.Origin.x = underlineFinalXPosition
}
}
vous pouvez l'utiliser
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!)
A.Jams répond pour Swift 5.1 Xcode 11.
import Foundation
extension UISegmentedControl {
func removeBorder(){
self.tintColor = UIColor.clear
self.backgroundColor = UIColor.clear
self.setTitleTextAttributes( [NSAttributedString.Key.foregroundColor : UIColor.stavkrugDarkBlue], for: .selected)
self.setTitleTextAttributes( [NSAttributedString.Key.foregroundColor : UIColor.gray], for: .normal)
if #available(iOS 13.0, *) {
self.selectedSegmentTintColor = UIColor.clear
}
}
func setupSegment() {
self.removeBorder()
let segmentUnderlineWidth: CGFloat = self.bounds.width
let segmentUnderlineHeight: CGFloat = 2.0
let segmentUnderlineXPosition = self.bounds.minX
let segmentUnderLineYPosition = self.bounds.size.height - 1.0
let segmentUnderlineFrame = CGRect(x: segmentUnderlineXPosition, y: segmentUnderLineYPosition, width: segmentUnderlineWidth, height: segmentUnderlineHeight)
let segmentUnderline = UIView(frame: segmentUnderlineFrame)
segmentUnderline.backgroundColor = UIColor.clear
self.addSubview(segmentUnderline)
self.addUnderlineForSelectedSegment()
}
func addUnderlineForSelectedSegment(){
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.stavkrugDarkBlue
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)
underline.frame.Origin.x = underlineFinalXPosition
}
}