UiView 和所有子视图的副本..无法按下复制的 UIButton

Copy of UiView and all subviews..Copied UIButton cannot be pressed

本质上,我使用下面的代码扩展来复制视图及其所有子视图。复制成功,我可以查看复制的视图。但是,无法按下每个复制视图上的按钮。该按钮只能在第一个原始(未复制)视图中按下。 如何让所有复制的按钮都处于活动状态?这甚至可能吗?

我已经在按钮及其父视图上尝试了 .isUserInteractionEnabled。

override func viewDidLoad(){
    super.viewDidLoad()
    view.isUserInteractionEnabled = true
    view.addSubview(containerScrollView)
    containerScrollView.addSubview(contentView)
    contentView.addSubview(stackMainView)
    let button = UIButton(frame: CGRect(x: 270, y: 200, width: 80, height: 40))
    let partLabel1 = UILabel(frame: CGRect(x:10, y: 10, width: 300, height: 50))
    let partLabel2 = UILabel(frame: CGRect(x:10, y: 50, width: 300, height: 50))
    partLabel1.text = "This should sit within part use :)"
    partLabel1.textColor = .white
    partLabel2.text = "This should also sit within part use :)"
    partLabel2.textColor = .white
    contentView.addSubview(button)
    contentView.addSubview(partLabel1)
    contentView.addSubview(partLabel2)
    part.addSubview(button)
    part.addSubview(partLabel1)
    part.addSubview(partLabel2)
    part.bringSubviewToFront(button)
    part.bringSubviewToFront(partUse3Label1)
    part.layer.zPosition = -1
    button.setTitle("Issue", for: .normal)
    button.backgroundColor = .orange
    button.leadingAnchor.constraint(equalTo: part.leadingAnchor).isActive = true
    button.trailingAnchor.constraint(equalTo: part.trailingAnchor).isActive = true
    button.bottomAnchor.constraint(equalTo: part.bottomAnchor).isActive = true
    button.topAnchor.constraint(equalTo: part.topAnchor).isActive = true
    button.heightAnchor.constraint(equalToConstant: 40).isActive = true
    button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
    button.isUserInteractionEnabled = true
    part.bringSubviewToFront(button)
    partLabel1.leadingAnchor.constraint(equalTo: part.leadingAnchor).isActive = true
    partLabel1.trailingAnchor.constraint(equalTo: part.trailingAnchor).isActive = true
    partLabel2.leadingAnchor.constraint(equalTo: part.leadingAnchor).isActive = true
    partLabel2.trailingAnchor.constraint(equalTo: part.trailingAnchor).isActive = true
    part.layoutIfNeeded()

    let copiedView = self.part.copyView()
    stackMainView.addArrangedSubview(part)
    stackMainView.addArrangedSubview(copiedView)
    containerScrollView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
    containerScrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = true
    containerScrollView.trailingAnchor.constraint(equalTo:self.view.trailingAnchor, constant: 0).isActive = true
    containerScrollView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
    contentView.topAnchor.constraint(equalTo: self.containerScrollView.topAnchor, constant: 0).isActive = true
    contentView.leadingAnchor.constraint(equalTo: self.containerScrollView.leadingAnchor, constant: 0).isActive = true
    contentView.trailingAnchor.constraint(equalTo:self.containerScrollView.trailingAnchor, constant: 0).isActive = true
    contentView.bottomAnchor.constraint(equalTo: self.containerScrollView.bottomAnchor, constant: 0).isActive = true
    contentView.widthAnchor.constraint(equalTo:self.view.widthAnchor, constant: 0).isActive = true

    stackMainView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 50).isActive = true
    stackMainView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 8).isActive = true
    stackMainView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -8).isActive = true
    stackMainView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -30).isActive = true

}



@objc func buttonAction(sender: UIButton!) {
    print("Button tapped")
}

var containerScrollView: UIScrollView = {
    let scrollView = UIScrollView()
    scrollView.translatesAutoresizingMaskIntoConstraints  = false
    scrollView.backgroundColor = .white
    scrollView.isScrollEnabled = true
    return scrollView
}()

var contentView: UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints  = false
    view.backgroundColor = UIColor.white
    return view
}()

let stackMainView: UIStackView = {
    let stackView = UIStackView()
    stackView.translatesAutoresizingMaskIntoConstraints = false
    stackView.backgroundColor = .random()
    return stackView

}()



let part: UIView  = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints  = false
    view.layer.cornerRadius = 4
    view.layer.masksToBounds = true
    view.backgroundColor = .random()

    return view
}()

复制视图的扩展。

extension UIView {
    func copyView<T: UIView>() -> T {
        return NSKeyedUnarchiver.unarchiveObject(with: 
               NSKeyedArchiver.archivedData(withRootObject: self)) as! T
    }
}

我希望在控制台中打印输出 "Button Tapped" 只有当我按下非复制视图上的按钮时才会发生这种情况。

由于这一切都是在viewDidLoad中完成的,所以我假设您每次要复制的视图都是相同的。

您的代码可能无法正常工作,因为 NSKeyedArchiver 未存档按钮的目标和选择器对。

您可以创建一个提供新 UIView 的方法:

func createPart() -> UIView {
    let part = UIView()
    part.translatesAutoresizingMaskIntoConstraints  = false
    part.layer.cornerRadius = 4
    part.layer.masksToBounds = true
    part.backgroundColor = .random()

    // The part below is copied from your viewDidLoad method
    // Include only those lines that create the part view.
    // I might have put more than you need. Check twice
    let button = UIButton(frame: CGRect(x: 270, y: 200, width: 80, height: 40))
    let partLabel1 = UILabel(frame: CGRect(x:10, y: 10, width: 300, height: 50))
    let partLabel2 = UILabel(frame: CGRect(x:10, y: 50, width: 300, height: 50))
    partLabel1.text = "This should sit within part use :)"
    partLabel1.textColor = .white
    partLabel2.text = "This should also sit within part use :)"
    partLabel2.textColor = .white
    part.addSubview(button)
    part.addSubview(partLabel1)
    part.addSubview(partLabel2)
    part.bringSubviewToFront(button)
    part.bringSubviewToFront(partUse3Label1)
    part.layer.zPosition = -1
    button.setTitle("Issue", for: .normal)
    button.backgroundColor = .orange
    button.leadingAnchor.constraint(equalTo: part.leadingAnchor).isActive = true
    button.trailingAnchor.constraint(equalTo: part.trailingAnchor).isActive = true
    button.bottomAnchor.constraint(equalTo: part.bottomAnchor).isActive = true
    button.topAnchor.constraint(equalTo: part.topAnchor).isActive = true
    button.heightAnchor.constraint(equalToConstant: 40).isActive = true
    button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
    button.isUserInteractionEnabled = true
    part.bringSubviewToFront(button)
    partLabel1.leadingAnchor.constraint(equalTo: part.leadingAnchor).isActive = true
    partLabel1.trailingAnchor.constraint(equalTo: part.trailingAnchor).isActive = true
    partLabel2.leadingAnchor.constraint(equalTo: part.leadingAnchor).isActive = true
    partLabel2.trailingAnchor.constraint(equalTo: part.trailingAnchor).isActive = true
    part.layoutIfNeeded()

    return part
}

然后在 viewDidLoad 中,您应该删除帮助创建 part 视图的代码行,只留下创建堆栈视图和主要内容视图的代码。然后你应该调用 createPart 两次,你有 2 个副本!

let part = createPart()
let copyOfPart = createPart()