不能 select tableview 单元格中的第二个项目超过 uiview

Can't select second item in tableview cell over uiview

任何人都请帮助我,我有一个下拉列表,但我不能 select 第二行。我不明白为什么,我尝试使用 bringSubviewsToFront 或返回。我尝试使用 layer.zPosition 它仍然不能 select 第二行,但是当我选择第一行时它起作用了。是我的自动布局设置不正确吗?

这是我的 ui 和代码设置

// This is my custom Button

class GDropdownSchedule: UIButton {
    let headerLbl   = GTitleLabel(name: "Schedule Type".localized(), fontSize: 13, color: #colorLiteral(red: 0.4588235294, green: 0.4941176471, blue: 0.5647058824, alpha: 1))
    let bodyLbl     = GSubtitleLabel(name: "Additional Note".localized(), fontSize: 16, color: #colorLiteral(red: 0.09803921569, green: 0.09803921569, blue: 0.09803921569, alpha: 1))
    let dropDownIV  = GIconImageView(img: #imageLiteral(resourceName: "down-chevron"))
    var isOpen              = false
    let dropView    = DropDownView()
    var delegate: AddScheduleVCDelegate?
    var height: NSLayoutConstraint!
    override init(frame: CGRect) {
        super.init(frame: frame)
        configure()
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    private func configure() {
        backgroundColor     = #colorLiteral(red: 0.9764705882, green: 0.9764705882, blue: 0.9764705882, alpha: 1)
        layer.cornerRadius  = 5
        layer.borderWidth   = 1
        layer.borderColor   = #colorLiteral(red: 0.9411764706, green: 0.9411764706, blue: 0.9450980392, alpha: 1)
        dropView.completion = { text in
            self.bodyLbl.text = text
            self.bodyLbl.font = UIFont(name: "NunitoSans-Regular", size: 12)
            self.delegate?.toggleHide(selected: text)
            self.dismissDropDown()
        }
    }
    override func didMoveToSuperview() {
        addSubview(headerLbl)
        headerLbl.anchor(top: topAnchor, trailing: nil, bottom: nil, leading: leadingAnchor, topPadding: 10, rightPadding: 0, bottomPadding: 0, leftPadding: 10, width: 70, height: 18)
        addSubview(bodyLbl)
        bodyLbl.anchor(top: headerLbl.bottomAnchor, trailing: nil, bottom: bottomAnchor, leading: leadingAnchor, topPadding: 2, rightPadding: 10, bottomPadding: 10, leftPadding: 10, width: 0, height: 0)
        addSubview(dropDownIV)
        dropDownIV.tintColor = #colorLiteral(red: 0.2549019608, green: 0.3019607843, blue: 0.3568627451, alpha: 1)
        dropDownIV.anchor(top: nil, trailing: trailingAnchor, bottom: bottomAnchor, leading: nil, topPadding: 0, rightPadding: 18, bottomPadding: 17, leftPadding: 0, width: 12, height: 10)
        addSubview(dropView)
        dropView.translatesAutoresizingMaskIntoConstraints = false
        dropView.layer.zPosition = 1
        height = dropView.heightAnchor.constraint(equalToConstant: 0)
        NSLayoutConstraint.activate([
            dropView.topAnchor.constraint(equalTo: headerLbl.bottomAnchor),
            dropView.leadingAnchor.constraint(equalTo: leadingAnchor),
            dropView.trailingAnchor.constraint(equalTo: trailingAnchor)
        ])
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if isOpen == false {
            isOpen = true
            NSLayoutConstraint.deactivate([height])
            if self.dropView.tableView.contentSize.height > 150 {
                height.constant = 150
            } else {
                height.constant = dropView.tableView.contentSize.height
            }
            NSLayoutConstraint.activate([height])
            UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
                self.dropView.layoutIfNeeded()
                self.dropView.center.y += self.dropView.frame.height / 2
            })
        } else {
            isOpen = false
            NSLayoutConstraint.deactivate([height])
            height.constant = 0
            NSLayoutConstraint.activate([height])
            UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
                self.dropView.center.y -= self.dropView.frame.height / 2
                self.dropView.layoutIfNeeded()
            })
        }
    }
    func dismissDropDown() {
        isOpen = false
        NSLayoutConstraint.deactivate([height])
        height.constant = 0
        NSLayoutConstraint.activate([height])
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
            self.dropView.center.y -= self.dropView.frame.height / 2
            self.dropView.layoutIfNeeded()
        })
    }
}
class DropDownView: UIView, UITableViewDelegate, UITableViewDataSource {
    let tableView           = UITableView()
    var options             = [String]()
    var completion: ((String) -> Void)?
    var isHideSchedule      = false
    override init(frame: CGRect) {
        super.init(frame: frame)
        configure()
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    private func configure() {
        translatesAutoresizingMaskIntoConstraints = false
        addSubview(tableView)
        tableView.backgroundColor = #colorLiteral(red: 0.9764705882, green: 0.9764705882, blue: 0.9764705882, alpha: 1)
        tableView.separatorStyle = .none
        tableView.delegate      = self
        tableView.dataSource    = self
        tableView.anchor(top: topAnchor, trailing: trailingAnchor, bottom: bottomAnchor, leading: leadingAnchor, topPadding: 0, rightPadding: 0, bottomPadding: 0, leftPadding: 0, width: 0, height: 0)
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return options.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel?.text = options[indexPath.row]
        cell.textLabel?.font = UIFont(name: "NunitoSans-Regular", size: 12)
        cell.textLabel?.textColor = #colorLiteral(red: 0.09803921569, green: 0.09803921569, blue: 0.09803921569, alpha: 1)
        cell.backgroundColor = #colorLiteral(red: 0.9764705882, green: 0.9764705882, blue: 0.9764705882, alpha: 1)
        return cell
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        completion?(options[indexPath.row])
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

// This is in my viewController, the chooseScheduleDropDown is my customButton
[chooseScheduleDropDown, entryView, chooseDateView, chooseClass, startTimeView, endTimeView, descriptionView, saveBtn].forEach {
            v in
            v.translatesAutoresizingMaskIntoConstraints = false
            scrollView.addSubview(v)
        }
        scrollView.insertSubview(entryView, belowSubview: chooseScheduleDropDown)

因为命中测试机制

您在按钮上添加 dropView GDropdownSchedule

布局是

        addSubview(dropView)
        dropView.translatesAutoresizingMaskIntoConstraints = false
        dropView.layer.zPosition = 1
        height = dropView.heightAnchor.constraint(equalToConstant: 0)
        NSLayoutConstraint.activate([
            dropView.topAnchor.constraint(equalTo: headerLbl.bottomAnchor),
            dropView.leadingAnchor.constraint(equalTo: leadingAnchor),
            dropView.trailingAnchor.constraint(equalTo: trailingAnchor)
        ])

从现有代码来看,

dropView 的框架部分超出 Button GDropdownSchedule 的边界。

所以你可以看到它,你点击不起作用。


覆盖命中测试机制即可

 class GDropdownSchedule: UIButton {

 // ...

   override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        // if the button is hidden/disabled/transparent it can't be hit
        if self.isHidden || !self.isUserInteractionEnabled || self.alpha < 0.01 { return nil }

        let dropViewF = dropView.frame


        var index = 9
        if bounds.contains(point){
            index = 0
        }

        if dropViewF.contains(point){
            index = 1
        }

        switch index {
        case 0:
            for subV in subviews.reversed(){
                let realPoint = subV.convert(point, from: self)
                let hit = subV.hitTest(realPoint, with: event)
                if let v = hit{
                    return v
                }
            }
            return self
        case 1:
            if dropView.alpha > 0.01{
                let realPoint = dropView.convert(point, from: self)
                let hit = dropView.hitTest(realPoint, with: event)
                if let v = hit{
                    return v
                }
            }
        default:
            ()
        }
        return nil
    }

 }

From Apple's Doc

hitTest(_:with:)

This method traverses the view hierarchy by calling the point(inside:with:) method of each subview to determine which subview should receive a touch event.

If point(inside:with:) returns true, then the subview’s hierarchy is similarly traversed until the frontmost view containing the specified point is found. If a view does not contain the point, its branch of the view hierarchy is ignored.

You rarely need to call this method yourself, but you might override it to hide touch events from subviews.