使用它自己的.xib文件的UIButton的IBAction

问题描述 投票:0回答:4

我想在我的应用程序中创建一个可重复使用的按钮,并计划使用它自己的.xib文件进行设计。问题是我无法将IBAction连接到使用它的控制器中的自定义按钮。

我创建了一个名为.xib的新SampleButton.xib文件,并添加了一个按钮。这是层次结构和视图的样子:

enter image description here

然后我创建了一个名为SampleButton.swift的新swift文件,其中有一个名为SampleButton的类,它是UIButton的子类,并在我的SampleButton.xib文件中将其指定为文件所有者。

SampleButton.swift的内容如下:

import Foundation
import UIKit

@IBDesignable
class SampleButton: UIButton {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    func setup() {
        guard let view = loadViewFromNib() as? UIButton else {
            return
        }
        view.frame = bounds
        view.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth,
                                 UIView.AutoresizingMask.flexibleHeight]
        addSubview(view)

        view.layer.borderWidth = 2
        view.layer.borderColor = UIColor.white.cgColor
    }

    func loadViewFromNib() -> UIView? {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
        return nib.instantiate(withOwner: self, options: nil).first as? UIButton
    }

    @IBAction func pressed(_ sender: Any) {
        print("Called in here")
    }
}

然后我可以在我的故事板中创建一个新按钮并将其设置为自定义,并将该类设置为SampleButton。但是现在如果我按住+从我的按钮拖动到相应的视图控制器为按钮创建一个IBAction,它就不会被调用。 SampleButton.swift文件中的那个是。即使我删除了IBAction文件中的SampleButton,它仍然没有被调用。

这里有什么帮助?我希望能够单独设计按钮,然后在控制器中使用IBactions

ios swift
4个回答
1
投票

我的一些自定义xib视图遇到了同样的问题,我最初的想法是我可以将我的xib设置为IBDesignable,然后在视图控制器中连接我的按钮的故事板渲染中的插座。

那没用。

所以我使用自定义视图中的委托回调设置了一些变通方法。我使用它们为视图控制器创建了IBOutlets视图,然后在viewDidLoad中我设置了委托并处理视图控制器中的按钮点击

import UIKit

// defines a callback protocol for the SampleButtonView
protocol SampleButtonViewDelegate: class {
    func sampleButtonTapped(_ button: SampleButton)
}

@IBDesignable
class SampleButton: UIView, NibLoadable {

    // create IBOutlet to button if you want to register a target/action directly
    @IBOutlet var button: UIButton!

    // set delegate if you want to handle button taps via delegate
    weak var delegate: SampleButtonViewDelegate?

    // initializers to make it so this class renders in view controllers
    // when using IBDesignable
    convenience init() {
        self.init(frame: .zero)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        loadFromNib(owner: self)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        loadFromNib(owner: self)
    }

    @IBAction func buttonTapped(_ sender: Any) {
        delegate?.sampleButtonTapped(_ button: self)
    }
}

// here's a sample ViewController using this view and the delegate callback method
class ViewController: UIViewController {

    @IBOutlet var sampleButtonView: SampleButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        sampleButtonView.delegate = self
    }
}

extension ViewController: SampleButtonViewDelegate {
    func sampleButtonTapped(_ button: SampleButton) {
        // TODO: run logic for button tap here
    }
}

为了完整起见,我还将在此处添加此NibLoadable协议定义。

// I used this for the @IBDesignable functionality to work and actually render 
// my xib layouts in the storyboard view controller layouts using this class
import UIKit

/// Defines an interface for UIViews defined in .xib files.
public protocol NibLoadable {

    // the name of the associated nib file
    static var nibName: String { get }

    // loads the view from the nib
    func loadFromNib(owner: Any?)
}

public extension NibLoadable where Self: UIView {

    /// Specifies the name of the associated .xib file.
    /// Defaults to the name of the class implementing this protocol.
    /// Provide an override in your custom class if your .xib file has a different name than it's associated class.
    static var nibName: String {
        return String(describing: Self.self)
    }

    /// Provides an instance of the UINib for the conforming class.
    /// Uses the bundle for the conforming class and generates the UINib using the name of the .xib file specified in the nibName property.
    static var nib: UINib {
        let bundle = Bundle(for: Self.self)
        return UINib(nibName: Self.nibName, bundle: bundle)
    }

    /// Tries to instantiate the UIView class from the .xib file associated with the UIView subclass conforming to this protocol using the owner specified in the function call.
    /// The xib views frame is set to the size of the parent classes view and constraints are set to make the xib view the same size as the parent view. The loaded xib view is then added as a subview.
    /// This should be called from the UIView's initializers "init(frame: CGRect)" for instantiation in code, and "init?(coder aDecoder: NSCoder)" for use in storyboards.
    ///
    /// - Parameter owner: The file owner. Is usually an instance of the class associated with the .xib.
    func loadFromNib(owner: Any? = nil) {
        guard let view = Self.nib.instantiate(withOwner: owner, options: nil).first as? UIView else {
            fatalError("Error loading \(Self.nibName) from nib")
        }
        view.frame = self.bounds
        view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        addSubview(view)
    }
}

您也可以简单地将您在视图控制器中定义的功能注册为自定义视图中按钮的目标/动作功能。

override func viewDidLoad() {
    super.viewDidLoad()

    mySampleButtonView.button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
}

@objc func buttonTapped(_ sender: UIButton) {
    // handle button tap action in view controller here...
}

1
投票
  1. 在nib类中创建按钮的iboutlet。
  2. 在你需要的viewcontroller中添加你的nib视图。
  3. 添加按钮插座的目标。

尝试以下代码:

override func viewDidLoad() {
    super.viewDidLoad()
let myButton = Bundle.main.loadNibNamed("myButtonxibName", owner: self, options: nil)?[0] as? myButtonxibClassName
myButton.button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
self.view.addsubview(myButton)
}
@objc func buttonTapped() {}

0
投票

您不需要Xib来完成您想要做的事情。从上面的班级中删除loadViewFromNib()pressed(_ sender: Any)函数。更改您的setup()方法以自定义您的按钮。我看到你要为它添加边框。做这样的事情:

func setup() {
    self.layer.borderWidth = 2
    self.layer.borderColor = UIColor.white.cgColor
    // * Any other UI customization you want to do can be done here * //
}

在你的故事板中,将常规UIButton拖放到你想要使用的任何地方,将属性检查器中的类设置为SampleButton,根据需要连接你的IBOutletIBActions,这应该是好的。


0
投票

我认为不可能这样做。更简单的方法是在视图控制器中设置目标和操作。就像是:

class VC: UIViewController {
    func viewDidLoad() {
       sampleButton.addTarget(self, action: #selector(didClickOnSampleButton))
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.