UIKit中复刻类UISegmentedView的自定义形状表单,有无更简便方案?
在UIKit中实现带类分段控件的非矩形表单:简化方案
不用一开始就考虑继承多个UIKit类,优先用组合现有控件+自定义遮罩的方式就能实现,代码简洁且易维护,以下是具体实现思路:
核心思路:拆分视觉元素,组合实现
把设计拆成两个独立部分处理,再通过布局和遮罩让它们视觉融合:
- 非矩形表单容器:用
UIBezierPath+CAShapeLayer做遮罩,给普通UIView赋予自定义形状 - 类分段控件:直接用系统
UISegmentedControl(或自定义按钮组),通过调整布局、外观让它和容器无缝衔接
代码示例(Swift)
// 1. 创建非矩形表单容器 let formContainer = UIView(frame: CGRect(x: 20, y: 100, width: 350, height: 400)) formContainer.backgroundColor = .white view.addSubview(formContainer) // 定义带顶部凹口的路径(适配分段控件的位置) let path = UIBezierPath() // 从分段控件高度下方开始绘制,留出凹口位置 path.move(to: CGPoint(x: 0, y: 60)) path.addLine(to: CGPoint(x: 80, y: 60)) // 绘制凹口曲线,匹配分段控件的底部形状 path.addQuadCurve(to: CGPoint(x: 120, y: 0), controlPoint: CGPoint(x: 100, y: 30)) path.addLine(to: CGPoint(x: 230, y: 0)) path.addQuadCurve(to: CGPoint(x: 270, y: 60), controlPoint: CGPoint(x: 250, y: 30)) path.addLine(to: CGPoint(x: formContainer.bounds.width, y: 60)) // 绘制容器剩余部分 path.addLine(to: CGPoint(x: formContainer.bounds.width, y: formContainer.bounds.height)) path.addLine(to: CGPoint(x: 0, y: formContainer.bounds.height)) path.close() // 给容器添加遮罩 let maskLayer = CAShapeLayer() maskLayer.path = path.cgPath formContainer.layer.mask = maskLayer // 2. 添加分段控件并匹配布局 let segmentedControl = UISegmentedControl(items: ["选项A", "选项B"]) // 把分段控件放在容器的凹口对应位置 segmentedControl.frame = CGRect(x: 80, y: 70, width: 190, height: 40) // 自定义外观让它和容器融合 segmentedControl.backgroundColor = .white segmentedControl.layer.cornerRadius = 8 segmentedControl.layer.borderWidth = 1 segmentedControl.layer.borderColor = UIColor.lightGray.cgColor segmentedControl.selectedSegmentIndex = 0 view.addSubview(segmentedControl)
进阶优化点
- 如果是自定义分段按钮组(而非系统控件):用
UIStackView包裹多个UIButton,同样给按钮组添加匹配容器形状的遮罩即可 - 交互联动:通过
addTarget监听分段控件的切换事件,动态调整表单内容,无需继承重写 - 适配不同屏幕:用AutoLayout替代硬编码frame,确保在不同设备上形状和布局保持一致
内容的提问来源于stack exchange,提问作者WebStormer
相关产品推荐
相关产品推荐

