如何更改UISegmentedControl的圆角半径?

53

能否改变UISegmentedControl的圆角半径?我已经尝试了下面的方法,这是我们用来改变UIView圆角半径的方法。

self.segmentedControl.layer.cornerRadius = 15.0;
self.segmentedControl.layer.masksToBounds = YES;

如您所见,这种方法无法正常工作,它只能裁剪UISegmentedControl的角落:

cut off corner

12个回答

109

这应该有效:

self.segmentedControl.layer.cornerRadius = 15.0;
self.segmentedControl.layer.borderColor = [UIColor whiteColor].CGColor;
self.segmentedControl.layer.borderWidth = 1.0f;
self.segmentedControl.layer.masksToBounds = YES;

在设置cornerRadius之后,您需要指定边框。


3
只有在想要增加圆角半径时才会起作用。 - Axel Guilmin
4
仅仅修剪角落并不能解决最初的问题。请看我下面的回答。 - Yakiv Kovalskyi
1
对于Swift: self.layer.cornerRadius = 15.0; self.layer.borderColor = UIColor.white.cgColor; self.layer.borderWidth = 1.0; self.layer.masksToBounds = true; - mondousage
@Manish 你怎么添加UISegmentedControl?我在iOS 13上尝试过,它运行良好。 - xi.lin
@user2185354,你能上传一个演示吗? - xi.lin
@Manish 请检查我的答案,通过设置CALayer的maskedCorners属性,可以编辑iOS 13及以上版本的圆角。https://dev59.com/b2Ag5IYBdhLWcg3wrMh4#60651341 - Lloyd Keijzer

38

iOS 13 / 14 - 终于可用了!!!

图片描述

我决定再试一次,终于完美解决了!!只有一行代码就解决了所有问题!请查看代码:

代码:

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)
    }
}

这个想法是使用UIImageView和自己的正方形图像和色调来选择移动的片段,我们想要做的是覆盖它的图像,以便我们可以控制颜色、角半径等。之后,我们想要删除一个苹果默认的三个动画之一(有问题的那一个会在触摸时使段落放大——我使用foregroundImageView.layer.animationKeys()找出哪些动画影响了移动的片段)。


圆角矩形已经可以使用了。但是你是如何更改所选索引的背景颜色的呢?在我的情况下,它适用于活动和非活动状态。 - Bishal Ghimire
如果我没记错的话,这是 foregroundImageView.backgroundColor = UIColor.darkGray 这一行。 - Merricat
嗨@RaimondoPrevidi,你有没有关于更改帧的解决方案? - Vishwanath Deshmukh
1
不,我暂时放弃了这个。我很快会将项目升级到iOS 14,然后再尝试一下,看看现在是否可行。 - Merricat
1
不需要图像扩展名 --> 将foregroundImageView的backgroundColor设置为某种颜色,将image设置为nil。 - Luchi Parejo Alcazar
显示剩余10条评论

35

将UISegmentedControl嵌入UIView中,并为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

被困 UISegmentedControl


6
请勿忘记在Storyboard中将剪辑子视图添加到UIView中。 - Ilario
@Ilario请解释一下。 - user5306470
这是在界面构建器中的一个设置。如果您不在父视图上启用它,子视图(UISegmentedControl)可能会超出父视图的边界。 - SkeletorFromEterenia

14

分段控件不会改变其绘制角落的方式,因此它会继续用自己的方式绘制角落,而你只是将其裁剪掉了。你不能控制分段控件如何绘制其边界形状。如果你真的不喜欢它的绘图方式,你必须从头开始设计自己的替代控件。你能够合法地做到的最接近你所尝试做的事情就是设置分段控件的背景图像。


3
我会将它传递给设计师 :) - Booharin

11

您可以通过增加其cornerRadius图层或从iOS 13及以上版本设置其maskedCorner属性来更改UISegmentedControl的边角半径。

此示例移除了默认的cornerRadius并将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


1
谢谢,但这并不影响“移动”段的角半径,只影响背景 :( 编辑:我终于找到了一种访问层次结构中“移动”视图的方法,使用 let movingSegment = subviews[numberOfSegments] as? UIimageView(基本上是段的背景,然后是移动的,然后是前景(即每个段的标题),所以“移动”视图总是在中间)。然后我将Image和highlightedImage设置为空UIImage(),将imageView的边界插入5,并将backgroundColor设置为所需的颜色。 - Merricat
它看起来完全符合预期,问题在于在点击动画期间,视图会变得与分段控件一样大,然后再次缩小,因此看起来不正确。请注意,我正在分段控件的layoutSubviews()中进行这些更改。请查看下面的答案以查看我的当前结果。 - Merricat
如果您为所选状态设置自定义背景图像,当移动时它是否仍会更改其角半径? @RaimondoPrevidi - Lloyd Keijzer
问题在于我想要标题,而不是图片。文档上说你只能选择其中一个。 - Merricat

6

已更新以符合Swift 3和Xcode 8.2的兼容性

mySegmentedControl.layer.cornerRadius = 25.0
mySegmentedControl.layer.borderColor = UIColor.white.cgColor
mySegmentedControl.layer.borderWidth = 1.0
mySegmentedControl.layer.masksToBounds = true

6
iOS13有一些变化,因此必须从layoutSubviews中设置borderRadius:
override func layoutSubviews() {
    super.layoutSubviews()
    layer.cornerRadius = 2
}

嘿,你有没有想过如何改变所选段视图的角半径? - Merricat
我不知道。我也不建议这样做。通过适当的工程时间,您可以创建任何布局,但这是否值得时间呢?我会倾向于让UX设计师朝着苹果内置的UX方向发展,并避免微小的定制化。 - mfaani
这真是太棒了,谢谢你的分享。注意:您也可以将其他设置器移动到layoutSubviews中,以便正确应用它们。我自己需要borderWidth。 - Sorin Dolha
@RaimondoPrevidi 请检查我的答案,以了解如何通过设置CALayer的maskedCorners属性从iOS 13及以上版本中编辑圆角 https://dev59.com/b2Ag5IYBdhLWcg3wrMh4#60651341 - Lloyd Keijzer
容易!非常感谢。 - Oscar Fernandez

4
以前的解决方案对我没有用。我的解决方案是:
UISegmentedControl 嵌入父视图中,然后将前导、尾随、底部、顶部的约束设置为 -1,以截断 UISegmentedControl 的边框。 最后,应该按照以下方式配置父视图:
segmentedControl.superview.clipsToBounds = true
segmentedControl.superview.layer.cornerRadius = 0 //whatever
segmentedControl.superview.layer.borderWidth = 1
segmentedControl.superview.layer.borderColor = segmentedControl.tintColor.CGColor

3

以下是针对 Yakiv的帖子 的代码转换和工作版本,适用于Swift 4.1和Xcode 9.3

segmentedOuterView.layer.cornerRadius = segmentedOuterView.bounds.height / 2
segmentedOuterView.layer.borderColor = UIColor.red.cgColor
segmentedOuterView.layer.borderWidth = 1
segmentedOuterView.layer.masksToBounds = true

3
你得到这个结果是因为其他东西(自定义绘图?)控制了边框而不是该层。幸运的是,似乎该层的设置具有优先级。
如果你知道需要什么边框颜色,你可以直接添加(例如):
self.segmentedControl.layer.borderColor = [UIColor whiteColor].CGColor;
self.segmentedControl.layer.borderWidth = 1.0;

1
如何更改圆角半径? - Julian
这不会改变圆角半径,只是补充问题中发布的原始代码以获得预期结果。 - Mihai Timar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接