【问题标题】:Set Action Listener Programmatically in Swift在 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; 
         } 

   } 
}; 

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

【问题讨论】:

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

标签: xcode swift


【解决方案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) { // 你的代码在这里 } ?
    猜你喜欢
    • 1970-01-01
    • 2020-02-26
    • 1970-01-01
    • 2010-11-14
    • 2021-07-02
    • 1970-01-01
    • 2015-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多