首页 > 解决方案 > 如何将数据作为参数发送到 UIButton 选择器方法

问题描述

因此,我正在构建一个类似于 Tinder 的应用程序,其中有一个卡片“甲板”(在此代码中称为 cardsDeckView),其中充满了 UIView(在此代码中称为 cardView)。这些“卡片”中的每一个都显示用户信息,例如个人资料图像(您可以循环浏览)、姓名、年龄和职业。他们还有一个按钮,按下该按钮后,将转到显示有关该用户的更多信息的用户信息屏幕。这是我遇到麻烦的地方。我想当用户加载到甲板上时,我可以将每个用户的 id 传递给每个相应的“卡片”,并在按下时通过按钮目标传递这些数据,但我在 Stack Overflow 上没有找到任何关于将参数传递给按钮选择器的信息迅速。这是我的代码,它实质上为现有用户加载了一些过滤器,

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。按下 moreInfo 按钮后,如何从 cardViews 获取这些 userId 并将它们传递给 UserDetails ViewController?我可以将目标/选择器添加到 cardView 中的这些按钮吗?任何建议都会有所帮助!谢谢!

标签: iosswift

解决方案


您不会将参数发送到按钮选择器。方法有一个固定的方法签名IBAction

IBAction是目标(通常是视图控制器)的方法。目标应保存您决定做什么所需的额外状态数据。

您发布了很多代码而没有太多解释,而我没有时间浏览该代码并弄清楚。

我收集到您在一个视图控制器上有一个按钮操作,需要链接到另一个视图控制器。第一个视图控制器应该知道它需要发送到另一个视图控制器的用户 ID。第一个视图控制器应该具有实例变量,使其能够访问该信息。您的IBAction方法可以访问实现这些IBActions 的对象的实例变量。


推荐阅读