簡體   English   中英

惰性按鈕的目標操作不起作用

[英]Target Action for lazy Button does not work

使用 Swift 5.1.3、iOS13.3、XCode11.3、

我嘗試創建一個簡單的按鈕目標操作。

但是,Button 在它自己的 StackView 類中,而且是一個惰性按鈕。

為什么目標操作在我的代碼中不起作用? callButtonMethod永遠不會被調用!

可能是因為 API 響應較晚,還是因為惰性按鈕無法執行目標操作。 我此刻一無所知。

感謝您對此的任何幫助。

這是我的代碼:

class CockpitHeaderStackView: UIStackView {

    weak var profileBtnDelegate: CallButtonProfileImage?

    var profileImageView = UIImageView()
    var profileName = "Cockpit".localized

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

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

    private func commonInit() {

        if let profile = MyAPI.profile, let person = profile.person {
            profileName = "\(person.firstName ?? "") \(person.lastName ?? "")"
        }

        MyAPI.getPicture(PictureType.avatar) { [weak self] (error, image) in

            guard let self = self else { return } // check if self still alive otherwise bail out

            DispatchQueue.main.async {

                if let image = image {
                    self.profileImageView.image = image
                } else {
                    self.profileImageView.image = #imageLiteral(resourceName: "profile-placeholder-small")
                }
                self.profileImageView.contentMode = .scaleAspectFill

                self.axis = .horizontal
                self.alignment = .bottom
                self.spacing = 10.0
                self.addArrangedSubview(self.titleLabel)
                self.addArrangedSubview(self.button)
            }
        }
    }

    lazy var titleLabel: UILabel = {
        let labelWidth: CGFloat = UIScreen.main.bounds.width - 16.0 - 10.0 - 36.0 - 16.0   // FullScreenWidth minus (Leading + Spacing + ButtonWidth + Trailing)
        let label = UILabel()
        label.font = AppConstants.Font.NavBar_TitleFont
        label.text = profileName
        label.textColor = .white
        label.tintColor = .white
        label.widthAnchor.constraint(equalToConstant: labelWidth).isActive = true
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    lazy var button: UIButton = {

        let buttonWidth: CGFloat = 36.0
        let button = UIButton(frame: CGRect(origin: .zero, size: CGSize(width: buttonWidth, height: buttonWidth)))

        button.setImage(self.profileImageView.image, for: .normal)
        button.addTarget(self, action: #selector(callButtonMethod), for: .touchUpInside)
        button.frame = CGRect(x: 0, y: 0, width: 36, height: 36)
        button.layer.cornerRadius = button.frame.size.width / 2
        button.layer.masksToBounds = false
        button.clipsToBounds = true

        button.translatesAutoresizingMaskIntoConstraints = false
        button.widthAnchor.constraint(equalToConstant: buttonWidth).isActive = true
        button.heightAnchor.constraint(equalToConstant: buttonWidth).isActive = true

        return button
    }()

    @objc func callButtonMethod() {
        profileBtnDelegate?.callProfileBtnMethod()
    }
}

CockpitHeaderStackView用於創建我的 ViewController 的自定義 NavigationBar。

這里是使用CockpitHeaderStackView的自定義 NavigationBar 的代碼:

protocol CallButtonProfileImage: AnyObject {
    func callProfileBtnMethod()
}

class MyViewController: UIViewController {

    // ...

    lazy var titleStackView: CockpitHeaderStackView = {
        let titleStackView = CockpitHeaderStackView(frame: CGRect(origin: .zero, size: CGSize(width: view.bounds.width, height: 88.0)))
        titleStackView.translatesAutoresizingMaskIntoConstraints = false
        return titleStackView
    }()

    lazy var cockpitHeaderView: UIView = {
        let cockpitHeaderView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: view.bounds.width, height: 88.0)))
        cockpitHeaderView.addSubview(titleStackView)
        titleStackView.leadingAnchor.constraint(equalTo: cockpitHeaderView.leadingAnchor, constant: 16.0).isActive = true
        titleStackView.topAnchor.constraint(equalTo: cockpitHeaderView.topAnchor).isActive = true
        titleStackView.trailingAnchor.constraint(equalTo: cockpitHeaderView.trailingAnchor, constant: -16.0).isActive = true
        titleStackView.bottomAnchor.constraint(equalTo: cockpitHeaderView.bottomAnchor).isActive = true
        return cockpitHeaderView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // ...

        view.clipsToBounds = true

        navigationController?.set_iOS12_lookAndFeel()
        navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
        navigationItem.largeTitleDisplayMode = .always
    }

    override func viewWillLayoutSubviews() {
        // replace NavBar title by custom cockpitHeaderView
        self.title = ""
        self.navigationItem.titleView = self.cockpitHeaderView
        // position the cockpitHeaderView inside the largeTitleDisplayMode NavBar
        self.cockpitHeaderView.translatesAutoresizingMaskIntoConstraints = false
        self.cockpitHeaderView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        if let navBarBottomAnchor = self.navigationController?.navigationBar.bottomAnchor {
            if UIScreen.main.bounds.height > 568.0 {
                self.cockpitHeaderView.topAnchor.constraint(equalTo: navBarBottomAnchor, constant: -48.0).isActive = true
            } else {
                self.cockpitHeaderView.topAnchor.constraint(equalTo: navBarBottomAnchor, constant: -46.0).isActive = true  // iPhone SE space limitation
            }
        } else {
            self.cockpitHeaderView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 89.0).isActive = true
        }
    }

    func callProfileBtnMethod() {
        print("right BarButton called here")
    }
}

我終於找到了“解決方案”:懶惰的初始化似乎是錯誤行為的原因。

事實上,當我替換所有惰性初始化並消除 StackView(稱為CockpitHeaderStackView )並將所有內容放入非惰性 let-constants 時,它就可以工作了!

這是最終的相關代碼(即我將所有內容都放在viewWillAppear方法中):

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let cardsHorizontalController = CardsHorizontalController()
    self.view.addSubview(cardsHorizontalController.view)
    cardsHorizontalController.view.translatesAutoresizingMaskIntoConstraints = false
    cardsHorizontalController.view.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 100.0).isActive = true
    cardsHorizontalController.view.heightAnchor.constraint(equalToConstant: 279).isActive = true
    cardsHorizontalController.view.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true

    navigationController?.set_iOS12_lookAndFeel()
    navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
    navigationItem.largeTitleDisplayMode = .always

    PeaxAPI.getPicture(PictureType.avatar) { [weak self] (error, image) in

        guard let self = self else { return } // check if self still alive otherwise bail out

        DispatchQueue.main.async {

            if let image = image {
                self.profileImageView.image = image
            } else {
                self.profileImageView.image = #imageLiteral(resourceName: "profile-placeholder-small")
            }
            self.profileImageView.contentMode = .scaleAspectFill

            if let profile = PeaxAPI.profile, let person = profile.person {
                self.profileName = "\(person.firstName ?? "") \(person.lastName ?? "")"
            }

            let titleStackView = UIStackView(frame: CGRect(origin: .zero, size: CGSize(width: self.view.bounds.width, height: 88.0)))
            titleStackView.isUserInteractionEnabled = true
            titleStackView.translatesAutoresizingMaskIntoConstraints = false

            titleStackView.axis = .horizontal
            titleStackView.alignment = .bottom
            titleStackView.spacing = 10.0

            let labelWidth: CGFloat = UIScreen.main.bounds.width - 16.0 - 10.0 - 36.0 - 16.0   // FullScreenWidth minus (Leading + Spacing + ButtonWidth + Trailing)
            let label = UILabel()
            label.font = AppConstants.Font.NavBar_TitleFont
            label.text = self.profileName
            label.textColor = .white
            label.tintColor = .white
            label.widthAnchor.constraint(equalToConstant: labelWidth).isActive = true
            label.translatesAutoresizingMaskIntoConstraints = false

            let buttonWidth: CGFloat = 36.0
            let button = UIButton(frame: CGRect(origin: .zero, size: CGSize(width: buttonWidth, height: buttonWidth)))

            button.setImage(self.profileImageView.image, for: .normal)
            button.isUserInteractionEnabled = true
            button.addTarget(self, action: #selector(self.callProfileBtnMethod), for: .touchUpInside)
            button.frame = CGRect(x: 0, y: 0, width: 36, height: 36)
            button.layer.cornerRadius = button.frame.size.width / 2
            button.layer.masksToBounds = false
            button.clipsToBounds = true

            button.translatesAutoresizingMaskIntoConstraints = false
            button.widthAnchor.constraint(equalToConstant: buttonWidth).isActive = true
            button.heightAnchor.constraint(equalToConstant: buttonWidth).isActive = true

            titleStackView.addArrangedSubview(label)
            titleStackView.addArrangedSubview(button)

            let cockpitHeaderView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: self.view.bounds.width, height: 88.0)))
            cockpitHeaderView.isUserInteractionEnabled = true
            cockpitHeaderView.addSubview(titleStackView)
            titleStackView.leadingAnchor.constraint(equalTo: cockpitHeaderView.leadingAnchor, constant: 16.0).isActive = true
            titleStackView.topAnchor.constraint(equalTo: cockpitHeaderView.topAnchor).isActive = true
            titleStackView.trailingAnchor.constraint(equalTo: cockpitHeaderView.trailingAnchor, constant: -16.0).isActive = true
            titleStackView.bottomAnchor.constraint(equalTo: cockpitHeaderView.bottomAnchor).isActive = true

            // replace NavBar title by custom cockpitHeaderView
            self.title = ""
            self.navigationItem.titleView = cockpitHeaderView
            cockpitHeaderView.sizeToFit()
        }
    }
}

我必須在將按鈕添加為子視圖后添加 addTarget 並且有效

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM