簡體   English   中英

如何將數據作為參數發送到 UIButton 選擇器方法

[英]How to Send Data as Parameter to UIButton Selector Method

所以我正在構建一個類似於 Tinder 的應用程序,其中有一個卡片“甲板”(在此代碼中稱為 cardsDeckView),其中填充了 UIView(在此代碼中稱為 cardView)。 這些“卡片”中的每一個都顯示用戶信息,例如個人資料圖像(您可以循環瀏覽)、姓名、年齡和職業。 它們上面還有一個按鈕,當按下該按鈕時,go 會轉到用戶信息屏幕,其中會顯示有關該用戶的更多信息。 這是我遇到麻煩的地方。 我想我可以在用戶加載到甲板上時將每個用戶的 ID 傳遞給每個相應的“卡片”,並在按下時通過按鈕目標傳遞此數據,但我沒有在 Stack Overflow 上找到任何關於將參數傳遞到按鈕選擇器的內容Swift。這是我的代碼,它基本上使用一些過濾器加載現有用戶,並使用每個用戶的信息創建 cardView:

import UIKit
import SDWebImage
import SLCarouselView
import JGProgressHUD

class DeckVC: UIViewController {

let headerView = UIView()
let cardsDeckView = SLCarouselView(coder: NSCoder.empty())
let menuView = BottomNavigationStackView()

var users: [User] = []

var userId: String?

let hud = JGProgressHUD(style: .extraLight)

override func viewDidLoad() {
    super.viewDidLoad()

    hud.textLabel.text = "Loading nearby users..."
    hud.layer.zPosition = 50
    hud.show(in: view)

    headerView.heightAnchor.constraint(equalToConstant: 70).isActive = true
    menuView.heightAnchor.constraint(equalToConstant: 70).isActive = true

    let stackView = UIStackView(arrangedSubviews: [headerView, cardsDeckView!, menuView])
    stackView.axis = .vertical
    view.addSubview(stackView)
    stackView.frame = .init(x: 0, y: 0, width: 300, height: 200)
    stackView.fillSuperview()
    stackView.isLayoutMarginsRelativeArrangement = true
    stackView.layoutMargins = .init(top: 0, left: 12, bottom: 0, right: 12)
    stackView.bringSubviewToFront(cardsDeckView!)

    menuView.settingsButton.addTarget(self, action: #selector(handleSettings), for: .touchUpInside)
    menuView.messagesButton.addTarget(self, action: #selector(handleMessages), for: .touchUpInside)

    setupUI()

}

func setupUI() {
    observeUsers { (user) in
        API.User.observeCurrentUser(completion: { (currentUser) in
            if (user.id != API.User.CURRENT_USER?.uid) && (currentUser.preferedGender == user.gender) && (currentUser.minAge!...currentUser.maxAge! ~= user.age!) {
                self.users.append(user)
                DispatchQueue.main.async {
                    self.setupCards()
                }
            } else if (user.id != API.User.CURRENT_USER?.uid) && (currentUser.preferedGender == "Both") && (currentUser.minAge!...currentUser.maxAge! ~= user.age!) {
                self.users.append(user)
                DispatchQueue.main.async {
                    self.setupCards()
                }
            }
        })
    }
}

func observeUsers(completion: @escaping (User) -> Void) {
    API.User.REF_USERS.observe(.childAdded) { (snapshot) in
        if let dict = snapshot.value as? [String : Any] {
            let user = User.transformUser(dict: dict, key: snapshot.key)
            completion(user)
        }
    }
}

@objc func handleSettings() {
    let transition = CATransition()
    transition.duration = 0.3
    transition.type = CATransitionType.push
    transition.subtype = CATransitionSubtype.fromLeft
    transition.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeInEaseOut)
    view.window!.layer.add(transition, forKey: kCATransition)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let profileVC = storyboard.instantiateViewController(withIdentifier: "ProfileVC")
    self.present(profileVC, animated: true, completion: nil)
}

@objc func handleMessages() {
    let transition = CATransition()
    transition.duration = 0.3
    transition.type = CATransitionType.push
    transition.subtype = CATransitionSubtype.fromRight
    transition.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeInEaseOut)
    view.window!.layer.add(transition, forKey: kCATransition)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let messagesVC = storyboard.instantiateViewController(withIdentifier: "MessagesVC")
    self.present(messagesVC, animated: true, completion: nil)
}

@objc func moreInfoTapped() {
    let userDetailsController = UserDetailsVC()
    userDetailsController.userId = userId
    present(userDetailsController, animated: true, completion: nil)
}

@objc func messageUserTapped() {
    let transition = CATransition()
    transition.duration = 0.3
    transition.type = CATransitionType.push
    transition.subtype = CATransitionSubtype.fromRight
    transition.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeInEaseOut)
    view.window!.layer.add(transition, forKey: kCATransition)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let messagesVC = storyboard.instantiateViewController(withIdentifier: "MessagesVC")
    let m = MessagesVC()
    m.userId = userId
    self.present(messagesVC, animated: true, completion: nil)

    // go to specific user chat after this transition
}

func setupCards() {
    for user in users {
        let gradientView = GlympsGradientView()
        let barsStackView = UIStackView()
        let moreInfoButton = UIButton(type: .system)
        moreInfoButton.setImage(#imageLiteral(resourceName: "info_icon").withRenderingMode(.alwaysOriginal), for: .normal)
        moreInfoButton.isUserInteractionEnabled = true
        moreInfoButton.addTarget(self, action: #selector(moreInfoTapped), for: .touchUpInside)
        let messageUserButton = UIButton(type: .system)
        messageUserButton.setImage(#imageLiteral(resourceName: "message-icon2").withRenderingMode(.alwaysOriginal), for: .normal)
        messageUserButton.isUserInteractionEnabled = true
        messageUserButton.addTarget(self, action: #selector(messageUserTapped), for: .touchUpInside)
        gradientView.layer.opacity = 0.5
        let cardView = CardView(frame: .zero)
        cardView.userId = user.id
        userId = user.id
        cardView.images = user.profileImages
        if let photoUrlString = user.profileImages {
            let photoUrl = URL(string: photoUrlString[0])
            cardView.imageView.sd_setImage(with: photoUrl)
        }
        (0..<user.profileImages!.count).forEach { (_) in
            let barView = UIView()
            barView.backgroundColor = UIColor(white: 0, alpha: 0.1)
            barView.layer.cornerRadius = barView.frame.size.height / 2
            barsStackView.addArrangedSubview(barView)
            barsStackView.arrangedSubviews.first?.backgroundColor = .white
        }

        let nametraits = [UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold]
        var nameFontDescriptor = UIFontDescriptor(fontAttributes: [UIFontDescriptor.AttributeName.family: "Avenir Next"])
        nameFontDescriptor = nameFontDescriptor.addingAttributes([UIFontDescriptor.AttributeName.traits: nametraits])

        let agetraits = [UIFontDescriptor.TraitKey.weight: UIFont.Weight.light]
        var ageFontDescriptor = UIFontDescriptor(fontAttributes: [UIFontDescriptor.AttributeName.family: "Avenir Next"])
        ageFontDescriptor = ageFontDescriptor.addingAttributes([UIFontDescriptor.AttributeName.traits: agetraits])

        let jobtraits = [UIFontDescriptor.TraitKey.weight: UIFont.Weight.light]
        var jobFontDescriptor = UIFontDescriptor(fontAttributes: [UIFontDescriptor.AttributeName.family: "Avenir Next"])
        jobFontDescriptor = jobFontDescriptor.addingAttributes([UIFontDescriptor.AttributeName.traits: jobtraits])

        let attributedText = NSMutableAttributedString(string: user.name!, attributes: [.font: UIFont(descriptor: nameFontDescriptor, size: 30)])
        attributedText.append(NSAttributedString(string: " \(user.age!)", attributes: [.font: UIFont(descriptor: ageFontDescriptor, size: 24)]))
        if user.profession != "" && user.company != "" {
            attributedText.append(NSAttributedString(string: "\n\(user.profession!) @ \(user.company!)", attributes: [.font: UIFont(descriptor: jobFontDescriptor, size: 20)]))
        }

        cardView.informationLabel.attributedText = attributedText

        // cardsDeckView.addSubview(cardView)
        cardView.addSubview(gradientView)
        cardView.addSubview(barsStackView)
        cardView.addSubview(moreInfoButton)
        cardView.addSubview(messageUserButton)
        cardView.moreInfoButton = moreInfoButton
        cardView.messageUserButton = messageUserButton
        cardView.stackView = barsStackView
        moreInfoButton.anchor(top: nil, leading: nil, bottom: cardView.bottomAnchor, trailing: cardView.trailingAnchor, padding: .init(top: 0, left: 0, bottom: 20, right: 20), size: .init(width: 50, height: 50))
        messageUserButton.anchor(top: cardView.topAnchor, leading: nil, bottom: nil, trailing: cardView.trailingAnchor, padding: .init(top: 25, left: 0, bottom: 0, right: 25), size: .init(width: 44, height: 44))
        barsStackView.anchor(top: cardView.topAnchor, leading: cardView.leadingAnchor, bottom: nil, trailing: cardView.trailingAnchor, padding: .init(top: 8, left: 8, bottom: 0, right: 8), size: .init(width: 0, height: 4))
        barsStackView.spacing = 4
        barsStackView.distribution = .fillEqually
        cardView.fillSuperview()
        gradientView.fillSuperview()

        hud.textLabel.text = "All done! \u{1F389}"
        hud.dismiss(afterDelay: 0.0)

        self.cardsDeckView?.appendContent(view: cardView)

    }
}

}

extension NSCoder {
class func empty() -> NSCoder {
    let data = NSMutableData()
    let archiver = NSKeyedArchiver(forWritingWith: data)
    archiver.finishEncoding()
    return NSKeyedUnarchiver(forReadingWith: data as Data)
}
}

extension Array {
public mutating func appendDistinct<S>(contentsOf newElements: S, where condition:@escaping (Element, Element) -> Bool) where S : Sequence, Element == S.Element {
    newElements.forEach { (item) in
        if !(self.contains(where: { (selfItem) -> Bool in
            return !condition(selfItem, item)
        })) {
            self.append(item)
        }
    }
}
}

請參閱 setupUsers(),並查看如何使用按鈕創建 cardView。 如何從 cardViews 中獲取這些 userIds 並在按下 moreInfo 按鈕后將它們傳遞給 UserDetails ViewController? 我可以將目標/選擇器添加到 cardView 中的這些按鈕嗎? 任何建議都會有所幫助! 謝謝!

這絕對有效!

在 setupCards() function 中,使用下面的代碼如下:按鈕層的名稱是字符串類型,它將包含您的用戶 ID 並使用它的層名稱進一步捕獲它。

    moreInfoButton.layer.name = user.id
    moreInfoButton.addTarget(self, action: #selector(moreInfoTapped(_:)), for: .touchUpInside)

在 moreInfoTapped 選擇器方法中,添加如下所述的參數並將其進一步傳遞給所需的 controller。

@objc func moreInfoTapped(_ sender: UIButton) {
let userDetailsController = UserDetailsVC()
userDetailsController.userId = sender.layer.name
present(userDetailsController, animated: true, completion: nil)

}

您不會將參數發送到按鈕選擇器。 IBAction方法有一個固定的方法簽名。

IBAction是目標(通常是視圖控制器)的方法。 目標應該包含決定做什么所需的額外狀態數據。

您發布了很多代碼而沒有太多解釋,我沒有時間仔細閱讀該代碼並弄清楚。

我猜你在一個視圖控制器上有一個按鈕動作,需要鏈接到另一個視圖控制器。 第一個視圖控制器應該知道它需要發送到另一個視圖控制器的用戶 ID。 第一個視圖控制器應該具有實例變量,使其能夠訪問該信息。 您的IBAction方法可以訪問實現這些IBAction的對象的實例變量。

有兩個問題。

首先,你想做的事情是不可能的。 您不能將額外數據傳遞到目標/操作按鈕事件調用中,因為它不是您的調用。 這是可可的召喚。

其次,您的操作方法簽名有缺陷:

@objc func moreInfoTapped() {

正確的簽名是:

@objc func moreInfoTapped(_ sender:Any) {

如果您以這種方式編寫操作方法,則可以檢索sender - 被點擊的特定按鈕。 現在您可以確定這是什么按鈕以及它在哪里等等,並確定您想要傳遞哪些數據作為響應。

您可以做的是創建一個自定義的 UIButton 類。 在該自定義按鈕類中創建所需的變量。 傳遞您的用戶 ID,添加 addTarget。

moreInfoButton.userId = user.id
moreInfoButton.addTarget(self, action: #selector(moreInfoTapped(_:)), for: .touchUpInside)

    class CustomButton: UIButton {
    var userId: String?

    }

    @objc func moreInfoTapped(_ sender: CustomButton) {
    print(sender.userId)
    }

暫無
暫無

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

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