自定义footerview不响应我的点击手势识别器标签

问题描述

所以我已经待了几天,没有运气。我有一个由xib文件制成的自定义UIView,并将其添加到footerView中。显示了该视图,但它没有响应我添加到ViewController类中的标签的手势识别器。在VC中,我创建了UIView的实例并将其添加到tableView中。

奇怪的是,当使用辅助功能检查器时,它确实会读取标签

这是containerView

class AdviceCardWidgetContainerCurvedView: UIView {
    
    struct Constants {
        static let nibName = "ClariContainerView"
        static let containerHeight: CGFloat =  169.0
        static let curvedPercent: CGFloat = 0.2
    }
    
    let nibName = "ClariContainerView"
    var clariView: UIView?
    var clariTitle: String?
    var clariQuestion: String?

    @IBOutlet weak var clariTitleLabel: UILabel!
    @IBOutlet weak var clariQuestionLabel: UILabel!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }


    private func applyCurve(givenView view: UIView,curvedPercent: CGFloat) {
        let shapeLayer = CAShapeLayer(layer: view.layer)
        shapeLayer.path = self.pathForCurvedView(givenView: view,curvedPercent: curvedPercent).cgPath
        shapeLayer.frame = view.bounds
        view.layer.mask = shapeLayer
        addSubview(view)
    }
    
    private func pathForCurvedView(givenView view: UIView,curvedPercent: CGFloat) -> UIBezierPath {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 0.0,y: 0.0))

        path.addLine(to: CGPoint(x: 0.0,y: view.bounds.size.height))
        path.addLine(to: CGPoint(x: UIScreen.main.bounds.width,y: 0.0))
        path.addQuadCurve(to: CGPoint(x: 0,y: 0),controlPoint: CGPoint(x: UIScreen.main.bounds.width / 2,y: view.bounds.size.height * curvedPercent))
        path.close()

        return path
    }
    
    private func commonInit() {
        guard let clariView = loadViewFromNib() else { return }
        clariView.frame = CGRect(x: 0,y: 0,width: UIScreen.main.bounds.width,height: containerHeight)
        clariView.backgroundColor = .lightGray
        applyCurve(givenView: clariView,curvedPercent: 0.1)
        addSubview(clariView)
        clariTitleLabel.text = "Ask TD Clari"
        clariQuestionLabel.text = "What is my balance"
    }
    
    func loadViewFromNib() -> UIView? {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: Constants.nibName,bundle: bundle)
        return nib.instantiate(withOwner: self,options: nil).first as? UIView
    }

}

这就是我的视图控制器内部

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!
    let curvedView = AdviceCardWidgetContainerCurvedView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    
    override func viewDidLayoutSubviews() {
        curvedView.clariTitleLabel.accessibilityTraits = .button
        curvedView.clariTitleLabel.isUserInteractionEnabled = true
        curvedView.clariTitleLabel.backgroundColor = .red
        curvedView.clariTitleLabel.addGestureRecognizer(UITapGestureRecognizer(target: self,action: #selector(footerLableTapped)))

        tableView.tableFooterView = UIView(frame: CGRect(x: 0,width: tableView.frame.width,height: 169))
        tableView.tableFooterView?.addSubview(curvedView)
    }
    
    @objc func footerLableTapped() {
        print("label tapped")
    }
    
    func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    
    func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
        cell.textLabel?.text = "1"
        return cell
    }
}

enter image description here

解决方法

好的,所以经过一周的尝试,我解决了这个问题。最后,向footerView添加自定义xib文件会导致一些错误并与autoLayout冲突。一切看起来都应该如此,但是对于您添加的子视图(如按钮和标签)而言,框架实际上是不存在的,因此无法对其进行点击。确保您从情节提要中引用了tableView或创建它的方式。

override func viewDidLoad() {
    super.viewDidLoad()
    
    let remainingBottomFooterSpace = remaingBottomFooterViewSpace(for: tableView)
    
    let footerView = UIView(frame: CGRect(x: 0,y: 0,width: tableView.frame.size.width,height: 169))
    footerView.backgroundColor = .clear
    applyCurve(givenView: footerView,curvedPercent: 0.04)
    
    let remainingFooterView = UIView(frame: CGRect(x: 0,y: 169,height: remainingBottomFooterSpace))
    remainingFooterView.backgroundColor = .lightGray

    let curve = UIView()
    curve.translatesAutoresizingMaskIntoConstraints = false
    curve.backgroundColor = .lightGray
    
    let icon = UIImageView()
    icon.translatesAutoresizingMaskIntoConstraints = false
    icon.image = UIImage(named: "mytd_clari")
    icon.contentMode = .scaleAspectFill
    curved.addSubview(icon)
    
    let button = UIButton()
    button.translatesAutoresizingMaskIntoConstraints = false
    button.isUserInteractionEnabled = true
    button.setTitle("Ask",for: .normal)
    button.titleLabel?.font = .systemFont(ofSize: 16.0,weight: .medium)
    button.setTitleColor(.blue,for: .normal)
    button.addTarget(self,action: #selector(footerLableTapped),for: .touchUpInside)
    
    let questionLabel = UILabel()
    questionLabel.translatesAutoresizingMaskIntoConstraints = false
    questionLabel.text = "What is my balance"
    questionLabel.textColor = .green
    questionLabel.font = .systemFont(ofSize: 13,weight: .regular)
    questionLabel.textAlignment = .center
    curve.addSubview(clariQuestionLabel)
    
    let buttonContainer = UIView(frame: CGRect(x: 0,width: self.tableView.frame.size.width,height: 169))
    curve.addSubview(buttonContainer)
    buttonContainer.addSubview(button)
    
    tableView.tableFooterView = footerView
    tableView.tableFooterView?.addSubview(remainingFooterView)
    tableView.tableFooterView?.addSubview(curve)
    
    NSLayoutConstraint.activate([
        footerView.trailingAnchor.constraint(equalTo: tableView.trailingAnchor),footerView.leadingAnchor.constraint(equalTo: tableView.leadingAnchor)
    ])
    
    NSLayoutConstraint.activate([
        curve.widthAnchor.constraint(equalToConstant: tableView.frame.size.width),curve.heightAnchor.constraint(equalToConstant: 169)
    ])
    
    NSLayoutConstraint.activate([
        icon.topAnchor.constraint(equalTo: curve.topAnchor,constant: 39),icon.widthAnchor.constraint(equalToConstant: 40),icon.heightAnchor.constraint(equalToConstant: 40),icon.centerXAnchor.constraint(equalTo: curve.centerXAnchor),])
    
    NSLayoutConstraint.activate([
        button.topAnchor.constraint(equalTo: icon.bottomAnchor),button.centerXAnchor.constraint(equalTo: icon.centerXAnchor)
    ])
    
    NSLayoutConstraint.activate([
        label.topAnchor.constraint(equalTo: button.bottomAnchor),label.centerXAnchor.constraint(equalTo: icon.centerXAnchor),])
}

如果要添加曲线,请使用以下方法:

func applyCurve(givenView view: UIView,curvedPercent: CGFloat) {
        let shapeLayer = CAShapeLayer(layer: view.layer)
        shapeLayer.path = self.pathForCurvedView(curvedPercent: curvedPercent).cgPath
        shapeLayer.frame = view.bounds
        view.layer.mask = shapeLayer
    }
    
func pathForCurvedView(curvedPercent: CGFloat) -> UIBezierPath {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 0.0,y: 0.0))

        path.addLine(to: CGPoint(x: 0.0,y: UIScreen.main.bounds.height))
        path.addLine(to: CGPoint(x: UIScreen.main.bounds.width,y: 0.0))
        path.addQuadCurve(to: CGPoint(x: 0,y: 0),controlPoint: CGPoint(x: UIScreen.main.bounds.width / 2,y: UIScreen.main.bounds.height * curvedPercent))
        path.close()

        return path
    }

如果要添加剩余的footerView空间,则为func

func remaingBottomFooterViewSpace(for tableView: UITableView) -> CGFloat {
        //Get content height & calculate new footer height
        let cells = tableView.visibleCells
        var height: CGFloat = 0
        for i in 0..<cells.count {
            height += cells[i].frame.height
        }
        height = tableView.bounds.height - ceil(height)
        
        //If theh footer new height is negative,we make it 0 since we don't need extra footer view anymore
        height = height > 0 ? height : 0
        return height
    }