You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为UISegmentedControl选中项添加自定义子视图及底部边框

嘿,我来帮你搞定这两个需求!看你已经完成了隐藏边框和自定义选中背景的工作,接下来咱们一步步实现剩下的功能:

一、为选中的Segment添加底部边框

我们可以在你的UISegmentedControl扩展里新增一个方法,用来给选中项添加底部边框,并且监听选中状态变化自动更新边框位置:

import UIKit
import Foundation

extension UISegmentedControl {
    // 你已有的removeBorders方法和imageWithColor方法保持不变
    func removeBorders() {
        setBackgroundImage(imageWithColor(color: backgroundColor ?? Constants.Color.mainNavBarBGColor), for: .normal, barMetrics: .default)
        setBackgroundImage(imageWithColor(color: Constants.Color.mainNavBarBGColor), for: .selected, barMetrics: .default)
        // 补充移除分割线的代码(如果需要)
        setDividerImage(imageWithColor(color: .clear), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
    }
    
    private func imageWithColor(color: UIColor) -> UIImage {
        let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        context?.setFillColor(color.cgColor)
        context?.fill(rect)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image ?? UIImage()
    }
    
    // 新增:添加选中项底部边框
    func addSelectedBottomBorder(color: UIColor, height: CGFloat = 2.0) {
        // 先移除旧的边框,避免重复叠加
        subviews.forEach { segment in
            segment.layer.sublayers?.filter { $0.name == "selectedBottomBorder" }.forEach { $0.removeFromSuperlayer() }
        }
        
        // 给当前选中的segment添加边框
        guard let selectedSegment = subviews.first(where: { $0.isSelected }) else { return }
        
        let borderLayer = CALayer()
        borderLayer.name = "selectedBottomBorder"
        borderLayer.frame = CGRect(
            x: 0,
            y: selectedSegment.frame.height - height,
            width: selectedSegment.frame.width,
            height: height
        )
        borderLayer.backgroundColor = color.cgColor
        selectedSegment.layer.addSublayer(borderLayer)
        
        // 监听选中变化,自动更新边框位置
        addTarget(self, action: #selector(updateSelectedBottomBorder(color:height:)), for: .valueChanged)
    }
    
    @objc private func updateSelectedBottomBorder(color: UIColor, height: CGFloat) {
        // 移除所有旧边框
        subviews.forEach { segment in
            segment.layer.sublayers?.filter { $0.name == "selectedBottomBorder" }.forEach { $0.removeFromSuperlayer() }
        }
        
        // 给新选中的segment添加边框
        guard let selectedSegment = subviews.first(where: { $0.isSelected }) else { return }
        
        let borderLayer = CALayer()
        borderLayer.name = "selectedBottomBorder"
        borderLayer.frame = CGRect(
            x: 0,
            y: selectedSegment.frame.height - height,
            width: selectedSegment.frame.width,
            height: height
        )
        borderLayer.backgroundColor = color.cgColor
        selectedSegment.layer.addSublayer(borderLayer)
    }
}

使用的时候,只需要在调用removeBorders()之后,再调用这个方法:

yourSegmentedControl.removeBorders()
yourSegmentedControl.addSelectedBottomBorder(color: .systemBlue, height: 2.5)
二、为选中的Segment添加自定义子视图

同样在扩展里新增方法,支持给选中项添加自定义视图,并且在选中切换时自动转移视图:

// 在UISegmentedControl扩展里继续添加:
func addCustomSubviewToSelectedSegment(_ subview: UIView) {
    // 先移除之前添加的自定义视图(用tag标记方便查找)
    subviews.forEach { segment in
        segment.subviews.filter { $0.tag == 999 }.forEach { $0.removeFromSuperview() }
    }
    
    // 添加到当前选中的segment
    guard let selectedSegment = subviews.first(where: { $0.isSelected }) else { return }
    
    subview.tag = 999
    subview.translatesAutoresizingMaskIntoConstraints = false
    selectedSegment.addSubview(subview)
    
    // 这里可以根据你的需求设置约束,示例是让视图居中
    NSLayoutConstraint.activate([
        subview.centerXAnchor.constraint(equalTo: selectedSegment.centerXAnchor),
        subview.centerYAnchor.constraint(equalTo: selectedSegment.centerYAnchor),
        subview.widthAnchor.constraint(equalToConstant: 24),
        subview.heightAnchor.constraint(equalToConstant: 24)
    ])
    
    // 监听选中变化,更新视图位置
    addTarget(self, action: #selector(updateCustomSubview(_:)), for: .valueChanged)
}

@objc private func updateCustomSubview(_ sender: UISegmentedControl) {
    // 找到之前的自定义视图并移除
    let existingSubview = sender.subviews.flatMap { $0.subviews }.first(where: { $0.tag == 999 })
    existingSubview?.removeFromSuperview()
    
    // 这里可以根据需求重新创建视图,或者保留原有视图的引用
    // 示例中我们重新创建一个简单的红色圆形视图
    let customView = UIView()
    customView.backgroundColor = .systemRed
    customView.layer.cornerRadius = 12
    sender.addCustomSubviewToSelectedSegment(customView)
}

使用示例:

// 创建一个自定义视图,比如UIImageView
let customIcon = UIImageView(image: UIImage(systemName: "checkmark"))
customIcon.tintColor = .white

yourSegmentedControl.addCustomSubviewToSelectedSegment(customIcon)

这样就能实现你要的两个效果啦!

内容的提问来源于stack exchange,提问作者SlavisaPetkovic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:31:36