繁体   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