How to change the corner radius of UISegmentedControl?
Solution 1
This should work:
self.segmentedControl.layer.cornerRadius = 15.0;
self.segmentedControl.layer.borderColor = [UIColor whiteColor].CGColor;
self.segmentedControl.layer.borderWidth = 1.0f;
self.segmentedControl.layer.masksToBounds = YES;
You need to specify the border after setting cornerRadius.
Solution 2
Embed UISegmentedControl inside UIView and set corner radius for UIView.
Objective-C
outerView.layer.cornerRadius = CGRectGetHeight(outerView.bounds) / 2;
outerView.layer.borderColor = [UIColor blueColor].CGColor;
outerView.layer.borderWidth = 1;
Swift
outerView.layer.cornerRadius = CGRectGetHeight(outerView.bounds) / 2
outerView.layer.borderColor = UIColor.blueColor().CGColor
outerView.layer.borderWidth = 1
Solution 3
iOS 13 / 14 - FINALLY WORKING!!!
I decided to give it another go, and I finally got it working perfectly!! There's one line of code that fixed it all! Check out the code
Code:
class CustomSegmentedControl: UISegmentedControl{
private let segmentInset: CGFloat = 5 //your inset amount
private let segmentImage: UIImage? = UIImage(color: UIColor.red) //your color
override func layoutSubviews(){
super.layoutSubviews()
//background
layer.cornerRadius = bounds.height/2
//foreground
let foregroundIndex = numberOfSegments
if subviews.indices.contains(foregroundIndex), let foregroundImageView = subviews[foregroundIndex] as? UIImageView
{
foregroundImageView.bounds = foregroundImageView.bounds.insetBy(dx: segmentInset, dy: segmentInset)
foregroundImageView.image = segmentImage //substitute with our own colored image
foregroundImageView.layer.removeAnimation(forKey: "SelectionBounds") //this removes the weird scaling animation!
foregroundImageView.layer.masksToBounds = true
foregroundImageView.layer.cornerRadius = foregroundImageView.bounds.height/2
}
}
}
extension UIImage{
//creates a UIImage given a UIColor
public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
color.setFill()
UIRectFill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let cgImage = image?.cgImage else { return nil }
self.init(cgImage: cgImage)
}
}
The idea is that Apple uses a UIImageView with its own square image and tint for the selected moving segment. What we want to do is instead overwrite its image so we have control on the color, corner radius, etc. After that, we want to remove one of Apple's 3 default animations (the one that was problematic made the segment scale up on touch -- I used foregroundImageView.layer.animationKeys()
to find out what animations were affecting the moving segment)
Solution 4
The segmented control is not going to change the way it draws its corners, so it is continuing to draw its corners in its own way and you are then cutting them off. You are not in charge of how a segmented control draws its boundary shape. If you truly don't like the way it's drawn, you'll have to devise your own substitute control from scratch. The closest you can legitimately come to the kind of thing you're trying to do is to set the segmented control's background image.
Solution 5
You're able to change the UISegmentedControl cornerRadius by increasing the layer its cornerRadius or from iOS 13 and above by setting the layer its maskedCorner property.
This example removes the default cornerRadius and straightens the backgroundImage:
if #available(iOS 13.0, *) {
segmentedControl.layer.maskedCorners = .init()
} else {
segmentedControl.layer.cornerRadius = 0
}
Source: https://developer.apple.com/documentation/quartzcore/calayer/2877488-maskedcorners
Comments
-
wz366 almost 2 years
Is it possible to change the corner radius of UISegmentedControl? I have tried the following approach which we use to change a UIView's corner radius.
self.segmentedControl.layer.cornerRadius = 15.0; self.segmentedControl.layer.masksToBounds = YES;
This did not work as you can see it only cuts off the UISegmentedControl's corner:
-
Julian over 9 yearshow does it change corner radius?
-
Mihai Timar over 9 yearsThis doesn't change the corner radius. It just supplements the original code posted in the question to get the expected result.
-
swathy krishnan almost 9 yearsThis will usually work . Provide your code so that i can look into it !
-
Axel Guilmin about 8 yearsIt works only if you want to increase the cornerRadius
-
Yakiv Kovalskyi about 8 yearsIt doesn't fix the initial problem with only corners being cut off. See my answer below.
-
Ilario over 7 yearsand don't forget to add Clip subviews to UIView in storyboard
-
swathy krishnan about 7 yearsCheck with some value for corner radius- segmentContrl.layer.cornerRadius = 3.0;
-
mondousage over 6 yearsFor Swift: self.layer.cornerRadius = 15.0; self.layer.borderColor = UIColor.white.cgColor; self.layer.borderWidth = 1.0; self.layer.masksToBounds = true;
-
Booharin over 4 yearsI will pass it to designers:)
-
Merricat over 4 yearshey, do you have any idea how to change the corner radius of the selectedSegment view?
-
mfaani over 4 yearsI don't know. I wouldn't recommend it either. With the right amount of engineering time you can create any layout, but is it worth the time? I would lean the UX desinger towards UX that Apple has built-in itself and avoid micro customazation
-
xi.lin about 4 years@Manish How do you add the UISegmentedControl? I've tried in iOS 13 and it works well.
-
Sorin Dolha about 4 yearsThis is gold, thank you for sharing. Note: you can move to layoutSubviews other setters too, to get them properly applied. I needed borderWidth myself.
-
xi.lin about 4 years@user2185354 Could you upload a demo?
-
Dani about 4 years@Ilario please explain
-
Lloyd Keijzer about 4 years@RaimondoPrevidi check my answer for editing the corner radius from iOS 13 and above by setting the CALayer its maskedCorners property stackoverflow.com/a/60651341/5324541
-
Lloyd Keijzer about 4 years@Manish check my answer for editing the corner radius from iOS 13 and above by setting the CALayer its maskedCorners property stackoverflow.com/a/60651341/5324541
-
Merricat about 4 yearsThanks, but that does not affect the corner radius of the "moving" segment, only the background ones :( Edit: I finally found a way to access the "moving" view in the hierarchy with
let movingSegment = subviews[numberOfSegments] as? UIimageView
(basically it's the segments' backgrounds, then the moving one, then the foregrounds (i.e. each segment's title), so the "moving" view is always in the middle). Then I set the Image and highlightedImage to and empty UIImage(), inset the imageView's bounds by 5, and set the backgroundColor to the desired color. -
Merricat about 4 yearsIt looks exactly as it should, the problem is that during the tap animation the view grows as large as the segmentedControl, then shrinks again, so it looks wrong. Note that I'm doing these changes in the segmentedControl's
layoutSubviews()
. Look at my answer below to see my current results. -
Lloyd Keijzer about 4 years@RaimondoPrevidi If u set a custom background image for the selected state is it still changing it's corner radius when moving?
-
Merricat about 4 yearsThe problem is that I want the title, not an image. And on the docs it says you can only have one or the other.
-
Bishal Ghimire almost 4 yearsThe round rect is working. But how did you change the background color of selected index. In my case is set for both active and inactive case.
-
Merricat almost 4 yearsIf I remember correctly, it's the
foregroundImageView.backgroundColor = UIColor.darkGray
line -
Vishwanath Deshmukh almost 4 yearsHi @RaimondoPrevidi Do you got any solution for that changing frame?
-
Merricat almost 4 yearsUnfortunately no. I just used what apple gave us, sacrificing the rounded corners. For me, it was not worth investing more hours to try and break apple's code.
-
GR1995 almost 4 yearsTake a look at this solution. kenb.us/… class SegmentedControlAnimationRemover { static var shared = SegmentedControlAnimationRemover() @objc func removeAnimation(_ control: UISegmentedControl) { control.layer.sublayers?.forEach { $0.removeAllAnimations() } } } segmentedControl.addTarget(SegmentedControlAnimationRemover.shared, action: #selector(SegmentedControlAnimationRemover.removeAnimation(_:)), for: .valueChanged)
-
Merricat almost 4 yearsI tried removing animations but it wasn’t changing anything. I’ll have to try this, maybe calling it on valueChanged might work.
-
Merricat almost 4 years@GR1995 So, right now I could only test this on a simulator, and it seems to work MUCH better, however I'm pretty sure I'm still noticing a small "growing" animation. I will test it on a device as soon as I can. I got frame drops from the simulator.
-
Merricat almost 4 years@GR1995 Ok so I tried it on my device and it doesn't change much. The weird animation between switching segments is definitely gone (there's still a bit of grow-shrink animation, but I think that's on me, probably due to changing its bounds in
layoutSubviews()
). Regardless, it still does its full awkward animation when tapping the currently selected segment (grows-shrinks a lot, in place). I tried with .allEvents but no changes. Also, for some reason, adding this code completely removed the sliding animation on my first segmented control, and only the first time I change its value. lol weird -
Merricat over 3 yearsNo, I let this one go for the time being. I'm soon upgrading the project to iOS 14, so I'll try this again and see if it's now doable
-
anoop4real over 3 years@Merricat I managed to achieve some radius stuff (ofcourse without animation) see my Gist: gist.github.com/anoop4real/deffa9bbed3741b6c3f19c07d8c87502 ... following this thread stackoverflow.com/questions/58315497/… + some tweaks
-
Merricat over 3 yearsCurrently not at home and can't try this... I got the round corners to work in my code above, but the problem was the weird animations when interacting with the segmented control! Does your code still have this animation issue?
-
Anil Kumar almost 3 years@Merricat, excellent solution. Did you tried to remove background light grey color
-
Merricat almost 3 years@AnilKumar Thanks! No, I didn't need to remove the grey background, so I never tried :)
-
Oscar Fernandez over 2 yearsEasy! Many thanks.
-
Malcolm Murray almost 2 yearsThis answer works well for me. Should be the accepted answer.