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

基于UIView的自定义Segment Control仅首个按钮可用问题排查

问题根源与修复方案

核心问题

你的自定义SegmentControl失效的核心原因是**layoutSubviews()方法中重复执行初始化选中状态的逻辑**:

  • 每次界面布局更新(如点击按钮触发动画、屏幕旋转)时,layoutSubviews()都会被调用,而你在其中重复执行setupFirstSelection(),强制将选中状态重置回startingIndex对应的默认按钮(索引0)。
  • 同时,每次布局都会给所有按钮设置普通状态图片,直接覆盖了之前设置的选中状态图片。

修复步骤

1. 精简layoutSubviews(),仅保留必要的布局后处理

移除重复的初始化逻辑,只保留依赖最终frame的圆角设置:

override func layoutSubviews() {
    super.layoutSubviews()
    // 仅在布局完成后设置圆角,避免frame未确定时圆角计算错误
    self.slideView.layer.cornerRadius = self.slideView.frame.height / 2.0
}

2. 将初始化逻辑移至setupView(),仅执行一次

把按钮图片初始化、首次选中状态设置移到setupView()末尾,确保只在视图初始化时执行:

private func setupView() {
    self.buttons = [button1, button2, button3, button4]
    self.buttonTitles = [buttonText1, buttonText2, buttonText3, buttonText4]
    self.buttonImages = [image1, image2, image3, image4]
    self.buttonSelectImages = [image1Selected, image2Selected, image3Selected, image4Selected]
    
    button1.sizeToFit()
    button2.sizeToFit()
    button3.sizeToFit()
    button4.sizeToFit()
    
    stackView.addArrangedSubview(button1)
    stackView.addArrangedSubview(button2)
    stackView.addArrangedSubview(button3)
    stackView.addArrangedSubview(button4)
    stackView.axis = .horizontal
    stackView.distribution = .fillProportionally
    stackView.alignment = .fill
    stackView.translatesAutoresizingMaskIntoConstraints = false
    
    self.addSubview(slideView)
    self.addSubview(stackView)
    stackView.pinEdges(to: self)
    
    button1.addTarget(self, action: #selector(CustomSegmentedView.buttonTapped(sender:)), for: .touchUpInside)
    button2.addTarget(self, action: #selector(CustomSegmentedView.buttonTapped(sender:)), for: .touchUpInside)
    button3.addTarget(self, action: #selector(CustomSegmentedView.buttonTapped(sender:)), for: .touchUpInside)
    button4.addTarget(self, action: #selector(CustomSegmentedView.buttonTapped(sender:)), for: .touchUpInside)
    
    // 初始化按钮普通状态图片(移至此处)
    button1.setImage(buttonImages[0], for: .normal)
    button2.setImage(buttonImages[1], for: .normal)
    button3.setImage(buttonImages[2], for: .normal)
    button4.setImage(buttonImages[3], for: .normal)
    
    // 设置首次选中状态(移至此处)
    self.setupFirstSelection()
}

3. 优化didSelectButton(at:)方法(可选但更严谨)

添加重复点击判断,确保旧按钮完全恢复未选中状态:

func didSelectButton(at index: Int) {
    guard index != currentIndex else { return } // 避免重复点击同一按钮
    
    self.delegate?.didSelectPage(index: index)
    
    let oldButton = self.buttons[self.currentIndex]
    let newButton = self.buttons[index]
    
    // 恢复旧按钮到未选中状态
    oldButton.setImage(self.buttonImages[self.currentIndex], for: .normal)
    oldButton.setTitle("", for: .normal)
    
    // 设置新按钮为选中状态
    newButton.setImage(self.buttonSelectImages[index], for: .normal)
    newButton.setTitle(self.buttonTitles[index], for: .normal)
    
    // 滑动背景动画
    UIView.animate(withDuration: 0.2) {
        self.slideView.frame = newButton.frame
        self.layoutIfNeeded()
    }
    
    self.currentIndex = index
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 16:15:48