J'essaie de passer un paramètre supplémentaire à l'action buttonClicked, mais je ne peux pas déterminer la syntaxe à utiliser dans Swift.
button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
Toute ma méthode buttonClicked:
func buttonClicked(sender:UIButton)
{
println("hello")
}
Quelqu'un a des idées?
Merci de votre aide.
Vous ne pouvez pas transmettre de paramètres personnalisés dans addTarget:
. Une alternative consiste à définir la propriété tag
de button et à travailler en fonction de la balise.
button.tag = 5
button.addTarget(self, action: "buttonClicked:",
forControlEvents: UIControlEvents.TouchUpInside)
Ou pour Swift 2.2 et supérieur:
button.tag = 5
button.addTarget(self,action:#selector(buttonClicked),
forControlEvents:.TouchUpInside)
Maintenant, faites la logique basée sur la propriété tag
@objc func buttonClicked(sender:UIButton)
{
if(sender.tag == 5){
var abc = "argOne" //Do something for tag 5
}
print("hello")
}
Si vous souhaitez envoyer des paramètres supplémentaires à la méthode buttonClicked, par exemple indexPath ou urlString, vous pouvez sous-classer UIButton:
class subclassedUIButton: UIButton {
var indexPath: Int?
var urlString: String?
}
Assurez-vous de changer la classe du bouton dans l'inspecteur d'identité en sous-classe UIButton. Vous pouvez accéder aux paramètres de la méthode buttonClicked à l'aide de sender.indexPath
ou sender.urlString
.
Remarque: Si votre bouton est à l'intérieur d'une cellule, vous pouvez définir la valeur de ces paramètres supplémentaires dans la méthode cellForRowAtIndexPath (où le bouton est créé).
J'apprécie que tout le monde dise utiliser des balises, mais vous devez vraiment étendre la classe UIButton et simplement y ajouter l'objet.
Les étiquettes sont un moyen sans espoir de contourner cela. Étendre le UIButton comme ceci (dans Swift 4)
import UIKit
class PassableUIButton: UIButton{
var params: Dictionary<String, Any>
override init(frame: CGRect) {
self.params = [:]
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
self.params = [:]
super.init(coder: aDecoder)
}
}
alors votre appel peut être appelé (NOTE THE deux points ":" dans Selector(("webButtonTouched:"))
)
let webButton = PassableUIButton(frame: CGRect(x:310, y:40, width:40, height:40))
webButton.setTitle("Visit",for: .normal)
webButton.addTarget(self, action: #selector(YourViewController.webButtonTouched(_:)), for:.touchUpInside)
webButton.params["myvalue"] = "bob"
puis enfin attraper tout cela ici
@IBAction func webButtonTouched(_ sender: PassableUIButton) {
print(sender.params["myvalue"] ?? "")
}
Vous faites cela une fois et vous l'utilisez tout au long de votre projet (vous pouvez même donner à la classe enfant un objet générique et mettre ce que vous voulez dans le bouton!). Ou utilisez l’exemple ci-dessus pour mettre un nombre inépuisable de paramètres clé/chaîne dans le bouton. Vraiment utile pour inclure des éléments tels que des URL, confirmer la méthodologie du message, etc.
En passant, il est important que la communauté SO
réalise cela. Il existe toute une génération de mauvaises pratiques coupées autour de l'Internet par un nombre alarmant de programmeurs qui ne comprennent pas/qui n'ont pas N'avez-vous pas appris/oublié le concept de object extensions
Pour Swift 3.0, vous pouvez utiliser ce qui suit
button.addTarget(self, action: #selector(YourViewController.YourMethodName(_:)), for:.touchUpInside)
func YourMethodName(_ sender : UIButton) {
print(sender.tag)
}
Swift 4.2
Résultat:
testButton.on(.touchUpInside) { (sender, event) in
// You can use any reference initialized before the code block here
// You can access self by adding [weak self] before (sender, event)
// You can then either make self strong by using a guard statement or use a optional operator (?)
print("user did press test button")
}
Dans le fichier UIButton+Events.Swift
j'ai créé une méthode d'extension pour UIButton
qui lie un UIControl.Event
à un gestionnaire d'achèvement appelé EventHandler
:
import UIKit
fileprivate var bindedEvents: [UIButton:EventBinder] = [:]
fileprivate class EventBinder {
let event: UIControl.Event
let button: UIButton
let handler: UIButton.EventHandler
let selector: Selector
required init(
_ event: UIControl.Event,
on button: UIButton,
withHandler handler: @escaping UIButton.EventHandler
) {
self.event = event
self.button = button
self.handler = handler
self.selector = #selector(performEvent(on:ofType:))
button.addTarget(self, action: self.selector, for: event)
}
deinit {
button.removeTarget(self, action: selector, for: event)
if let index = bindedEvents.index(forKey: button) {
bindedEvents.remove(at: index)
}
}
}
private extension EventBinder {
@objc func performEvent(on sender: UIButton, ofType event: UIControl.Event) {
handler(sender, event)
}
}
extension UIButton {
typealias EventHandler = (UIButton, UIControl.Event) -> Void
func on(_ event: UIControl.Event, handler: @escaping EventHandler) {
bindedEvents[self] = EventBinder(event, on: self, withHandler: handler)
}
}
La raison pour laquelle j'ai utilisé une classe personnalisée pour lier l'événement est de pouvoir disposer de la référence ultérieurement lorsque le bouton est désintialisé. Cela évitera une éventuelle fuite de mémoire. Cela n'était pas possible dans l'extension UIButton
, car je ne suis pas autorisé à implémenter une propriété ni la méthode deinit
.
Dans Swift 3, créez un sélecteur comme celui-ci:
button.addTarget(self, action: #selector(ViewController.multipleParamSelector(_:secondParams:)), for: .touchUpInside)
Et attrapez l'événement comme ça:
func multipleParamSelector(_ sender: AnyObject, secondParams: AnyObject) {
}
code Swift 4.0 (nous y revoilà)
L'action appelée doit être marquée comme ceci car c'est la syntaxe de la fonction Swift pour exporter des fonctions en langage Objective C.
@objc func deleteAction(sender: UIButton) {
}
créer un bouton de travail:
let deleteButton = UIButton(type: .roundedRect)
deleteButton.setTitle("Delete", for: [])
deleteButton.addTarget(self, action: #selector(
MyController.deleteAction(sender:)), for: .touchUpInside)
Si vous avez une boucle de boutons comme moi, vous pouvez essayer quelque chose comme ça
var buttonTags:[Int:String]? // can be [Int:Any]
let myArray = [0:"a",1:"b"]
for (index,value) in myArray {
let button = // Create a button
buttonTags?[index] = myArray[index]
button.tag = index
button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchDown)
}
@objc func buttonAction(_ sender:UIButton) {
let myString = buttonTags[sender.tag]
}
Swift 5.0 code
J'utilise theButton.tag mais si j'ai beaucoup d'options, son cas sera très long.
theButton.addTarget(self, action: #selector(theFunc), for: .touchUpInside)
theButton.frame.name = "myParameter"
.
@objc func theFunc(sender:UIButton){
print(sender.frame.name)
}
Pour Swift 2.X et ci-dessus
button.addTarget(self,action:#selector(YourControllerName.buttonClicked(_:)),
forControlEvents:.TouchUpInside)
code Swift 3.
self.timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector:#selector(fetchAutocompletePlaces(timer:)), userInfo:[textView.text], repeats: true)
func fetchAutocompletePlaces(timer : Timer) {
let keyword = timer.userInfo
}
Vous pouvez envoyer une valeur dans 'userinfo' et l'utiliser comme paramètre dans la fonction.