在 Swift 中以编程方式设置动作监听器

Posted

技术标签:

【中文标题】在 Swift 中以编程方式设置动作监听器【英文标题】:Set Action Listener Programmatically in Swift 【发布时间】:2014-12-09 03:57:53 【问题描述】:

我看到一些示例代码将相同的 OnClick 事件分配给 android 中的所有按钮(即使它们执行完全不同的操作)。如何用 Swift 做到这一点

Android 示例:

@Override 
public void onCreate(Bundle savedInstanceState) 
        button1.setOnClickListener(onClickListener);
        button2.setOnClickListener(onClickListener);
        button3.setOnClickListener(onClickListener);
 

private OnClickListener onClickListener = new OnClickListener() 
     @Override 
     public void onClick(View v) 
         switch(v.getId())
             case R.id.button1:
                  //DO something 
             break; 
             case R.id.button2:
                  //DO something 
             break; 
             case R.id.button3:
                  //DO something 
             break; 
          

    
; 

注意:我不想以编程方式创建按钮。

【问题讨论】:

How create button programmatically in Swift?的可能重复 不...我需要为多个按钮添加相同的侦听器...这不是重复的。 在每个指向同一个动作的按钮上调用addTarget方法? UIcontrol 有一个方法 -addTarget 可以指向同一个“监听器”UIControl。但是从您的代码来看,为什么不使用 4 个侦听器而不是一个确定按下哪个按钮的侦听器? @cream-corn 因为您可能有一个动态表结构,其中包含可以使用行索引映射的按钮。 【参考方案1】:

ios 上,您没有设置监听器;您将目标(对象)和操作(方法签名,iOS 用语中的“选择器”)添加到您的 UIControlUIButton 是其子类):

button1.addTarget(self, action: "buttonClicked:", for: .touchUpInside)
button2.addTarget(self, action: "buttonClicked:", for: .touchUpInside)
button3.addTarget(self, action: "buttonClicked:", for: .touchUpInside)

第一个参数是目标对象,在本例中为self。该操作是一个选择器(方法签名),基本上有两个选项(稍后会详细介绍)。 control event 有点特定于 UIControl - .TouchUpInside 通常用于点击按钮。

现在,行动。这是以下格式之一的方法(名称由您选择):

func buttonClicked()
func buttonClicked(_ sender: AnyObject?)

要使用第一个使用“buttonClicked”,第二个(你想要的)使用“buttonClicked:”(带有尾随冒号)。 sender 将是事件的来源,也就是您的按钮。

func buttonClicked(_ sender: AnyObject?) 
  if sender === button1 
    // do something
   else if sender === button2 
    // do something
   else if sender === button3 
    // do something
  

(假设button1button2button3 是实例变量)。

考虑为每个按钮使用单独的方法,而不是使用大 switch 语句的这种方法。根据您的具体用例,两种方法都可能更好:

func button1Clicked() 
  // do something


func button2Clicked() 
  // do something


func button3Clicked() 
  // do something

在这里,我什至没有使用 sender 参数,因为我不需要它。

P.S.:您可以在 Storyboard 或 nib 文件中添加目标和操作,而不是以编程方式添加。为了公开您在函数前面放置IBAction 的操作,例如:

@IBAction func button1Clicked() 
  // do something

【讨论】:

【参考方案2】:

Swift 4.*

button.addTarget(self, action: #selector(didButtonClick), for: .touchUpInside)

并且按钮触发了这个功能:

@objc func didButtonClick(_ sender: UIButton) 
    // your code goes here

【讨论】:

现在应该写成 #selector(buttonClicked(sender:)) 或使用 #selector(buttonClicked(:)) btnAll.addTarget(self, action: #selector(buttonClicked( i>:)), for: .touchUpInside) 然后改变你的函数,比如 func buttonClicked(_ sender : UIButton) .... 如果我为所有按钮设置了相同的功能,如何检查单击了哪个按钮? 要检查单击了哪个按钮,您在创建它们时设置了不同的标签。 button.tag = 1(或 2 或 3)。然后你使用:switch sender.tag case 1:...【参考方案3】:

Swift 5 扩展解决方案

创建一个 SwiftFile "SetOnClickListener.swift" 复制粘贴此代码

import UIKit

class ClosureSleeve 
  let closure: () -> ()

  init(attachTo: AnyObject, closure: @escaping () -> ()) 
    self.closure = closure
    objc_setAssociatedObject(attachTo, "[\(arc4random())]", self, .OBJC_ASSOCIATION_RETAIN)
  

  @objc func invoke() 
    closure()
  


extension UIControl 
    func setOnClickListener(for controlEvents: UIControl.Event = .primaryActionTriggered, action: @escaping () -> ()) 
        let sleeve = ClosureSleeve(attachTo: self, closure: action)
        addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
    

如何使用 例如 buttonA 是一个 UIButton

buttonA.setOnClickListener 
  print("button A clicked")                  

【讨论】:

如何获取目标元素,例如@objc func didButtonClick(_ sender: UIButton) // 你的代码在这里 ?

以上是关于在 Swift 中以编程方式设置动作监听器的主要内容,如果未能解决你的问题,请参考以下文章

在 Android 中以编程方式创建的多个文本视图的单个 onclick 侦听器

在 Swift 中以编程方式设置 tabBarItem 标题

如何在 Swift 中以编程方式在水平线上设置约束? [关闭]

尝试在 Swift 中以编程方式设置 rightBarButton

在 Swift 中以编程方式为 CollectionView 设置插图

在 Swift 中以编程方式设置 XIB 文件的约束