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

自定义UITableViewCell子视图无法识别Tap手势问题求助

自定义UITableViewCell子视图Tap手势无法触发问题

在iOS开发中,我使用自定义MonthlyViewCell作为UITableView的单元格,该单元格内包含多个UIStackView,每个StackView中都有UIImageView类型的符号视图。我希望给这些符号视图添加Tap手势识别,但只有单元格自身的手势能正常工作,所有子视图(符号视图、StackView)的手势都无法触发,断点显示手势触发方法从未被调用。

已尝试的调试操作

  • 为所有相关视图设置isUserInteractionEnabled = true;
  • 调整子视图frame,确保其完全包含在父视图范围内;
  • 修改手势创建逻辑,将UITapGestureRecognizer实例的创建移至循环内部,为每个符号视图单独分配手势实例;
  • 检查约束配置,避免StackView超出父视图范围;

相关代码

MonthlyViewCell完整代码

class MonthlyViewCell: UITableViewCell {

  private let someSymbol: UIImageView = { 
    guard let image = UIImage(systemName: "j.circle.fill") else {return nil}
    
    let config = UIImage.SymbolConfiguration(pointSize: 27)
    let newImage = image.applyingSymbolConfiguration(config)
    
    let view = UIImageView(image: newImage)
    
    view.frame = CGRect(x: 0, y: 0, width: 10, height: 10)
    view.contentMode = .scaleAspectFit
    view.tag = 1
    view.isUserInteractionEnabled = true
    
    return view
  }()
  .
  .
  // other symbols

  private var delegate: MonthlyViewCellDelegate?

  private var stackViewOne = UIStackView()
  private var stackViewTwo = UIStackView()
  private var stackViewThree = UIStackView()

  override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
      super.init(style: style, reuseIdentifier: reuseIdentifier)
    
      commonInit()
  }

  required init?(coder: NSCoder) {
      super.init(coder: coder)
  }

  private func commonInit() {
      bounds = CGRect(x: 0, y: 0, width: 320, height: 120)
      frame = bounds
      print(frame)
    
      configureSubViews()
    
      addSubview(stackViewOne)
      addSubview(stackViewTwo)
      addSubview(stackViewThree)
    
      //addTargetToSymbols()
      activateConstraints()
    
      stackViewOne.frame = CGRect(x: 0, y: 0, width: frame.width-1, height: 15)
      stackViewTwo.frame = CGRect(x: 0, y: 0, width: frame.width-1, height: 15)
      stackViewThree.frame = CGRect(x: 0, y: 0, width: frame.width-1, height: 15)
    
      let gestureRecognizer = UITapGestureRecognizer()
      gestureRecognizer.addTarget(self, action: #selector(testTapped(sender:)))
    
      stackViewTwo.addGestureRecognizer(gestureRecognizer)
  }

  private func configureSubViews() {
      stackViewOne.translatesAutoresizingMaskIntoConstraints = false
      stackViewTwo.translatesAutoresizingMaskIntoConstraints = false
      stackViewThree.translatesAutoresizingMaskIntoConstraints = false
    
      stackViewOne.axis = .horizontal
      stackViewTwo.axis = .horizontal
      stackViewThree.axis = .horizontal
    
      stackViewOne.spacing = 60
      stackViewTwo.spacing = 60
      stackViewThree.spacing = 60
    
      let viewsOne = [januarySymbol, februarySymbol, marchSymbol, aprilSymbol]
      let viewsTwo = [maySymbol, juneSymbol, julySymbol, augustSymbol]
      let viewsThree = [septemberSymbol, octoberSymbol, novemberSymbol, decemberSymbol]
    
      let stackViews = [stackViewOne,stackViewTwo,stackViewThree]
    
      for one in viewsOne {
          stackViewOne.addArrangedSubview(one!)
      }
    
      for two in viewsTwo {
          stackViewTwo.addArrangedSubview(two!)
      }
    
      for three in viewsThree {
          stackViewThree.addArrangedSubview(three!)
      }
    
      /*for view in stackViews {
          bringSubviewToFront(view)
      }*/
  }

  private func activateConstraints() {
      let array: [NSLayoutConstraint] = [
        stackViewOne.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor),
        stackViewTwo.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor),
        stackViewThree.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor),
        
          stackViewOne.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 25),
          stackViewTwo.topAnchor.constraint(equalTo: stackViewOne.bottomAnchor, constant: 25),
          stackViewThree.topAnchor.constraint(equalTo: stackViewTwo.bottomAnchor, constant: 25)
    ]
    
      NSLayoutConstraint.activate(array)
  }

  private func addTargetToSymbols() {
      let gestureRecognizer = UITapGestureRecognizer()
    
      let symbols: [UIImageView?] = [januarySymbol, februarySymbol, marchSymbol, aprilSymbol, maySymbol, juneSymbol, julySymbol, augustSymbol, septemberSymbol, novemberSymbol, decemberSymbol]
    
      for symbol in symbols {
          guard let symbol = symbol else {return}
        
          gestureRecognizer.addTarget(self, action: #selector(monthSymbolTapped(sender:)))
          symbol.addGestureRecognizer(gestureRecognizer)
        
          bringSubviewToFront(symbol)
      }
  }

  @objc func testTapped(sender: UITapGestureRecognizer) {
      print("tapped")
  }

  func setDelegate(delegate: MonthlyViewCellDelegate) {
      self.delegate = delegate
  }

}

补充说明

  • 委托方法已在视图控制器中实现,控制器的View为UITableView,单元格在cellForRowAt方法中初始化。
  • 曾尝试修改addTargetToSymbols方法,为每个符号视图单独创建手势实例,代码如下,但问题仍未解决:
private func addTargetToSymbols() {
      let symbols: [UIImageView?] = [januarySymbol, februarySymbol, marchSymbol, aprilSymbol, maySymbol, juneSymbol, julySymbol, augustSymbol, septemberSymbol, novemberSymbol, decemberSymbol]

      for symbol in symbols {
          guard let symbol = symbol else {return}
          let gestureRecognizer = UITapGestureRecognizer()

          gestureRecognizer.addTarget(self, action: #selector(monthSymbolTapped(sender:)))
          symbol.addGestureRecognizer(gestureRecognizer)

          bringSubviewToFront(symbol)
      }
  }

手势触发方法代码

@objc func monthSymbolTapped(sender: UIGestureRecognizer) {
        print("tst")
        guard let tag = sender.view?.tag else {return}
        
        switch tag {
        case 1:
            delegate?.pushToYearlyVisits(month: tag)

        // other cases

        default:
            return
        }
    }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 03:10:15