因此,我正在构建一个与Tinder类似的应用程序,其中有一张卡片“ deck”(在此代码中称为cardsDeckView),其中填充了UIViews(在此代码中称为cardView)。这些“卡片”中的每一个都显示用户信息,例如个人资料图像(可以循环显示),姓名,年龄和职业。它们上还有一个按钮,当按下按钮时,该按钮会转到用户信息屏幕,其中显示有关该用户的更多信息。这是我遇到麻烦的地方。我以为可以在将用户加载到平台上时将每个用户的ID传递给每个相应的“卡”,并在按下该按钮时将这些数据传递给按钮目标,但是我在Stack Overflow上找不到任何有关将参数传递给按钮选择器的内容迅速。这是我的代码,本质上是使用一些过滤器加载现有用户,并使用每个用户的信息创建cardViews:
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的这些按钮中添加目标/选择器吗?任何建议都会有所帮助!谢谢!
答案 0 :(得分:0)
您不将参数发送到按钮选择器。 IBAction
方法有固定的方法签名。
IBAction
是目标(通常是视图控制器)的方法。目标应保存您需要决定做什么的其他状态数据。
您发布了很多代码而没有太多解释,而我没有时间去仔细研究一下代码。
我收集到您对一个视图控制器有一个按钮操作,该按钮需要链接到另一个视图控制器。第一个视图控制器应该知道它需要发送给另一个视图控制器的用户ID。第一个视图控制器应具有实例变量,以使其可以访问该信息。您的IBAction
方法可以访问实现这些IBAction
的对象的实例变量。
答案 1 :(得分:0)
有两个问题。
首先,您想做的事情是不可能的。您不能将额外的数据传递到目标/操作按钮事件调用中,因为它不是您的调用。是可可的电话。
第二,您的操作方法签名有缺陷:
@objc func moreInfoTapped() {
正确的签名是:
@objc func moreInfoTapped(_ sender:Any) {
如果以这种方式编写操作方法,则可以检索sender
(已轻按的特定按钮)。现在,您可以确定这是什么按钮,它在哪里,等等,并找出您想传递的数据作为响应。
答案 2 :(得分:0)
您可以做的是创建UIButton的自定义类。在该自定义按钮类中创建所需的变量。 传递您的userId,添加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)
}