Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/115.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何将UIViewController添加为以编程方式创建的UIView中创建的UIButton操作的目标?_Ios_Iphone_Objective C_Uiview_Uibutton - Fatal编程技术网

Ios 如何将UIViewController添加为以编程方式创建的UIView中创建的UIButton操作的目标?

Ios 如何将UIViewController添加为以编程方式创建的UIView中创建的UIButton操作的目标?,ios,iphone,objective-c,uiview,uibutton,Ios,Iphone,Objective C,Uiview,Uibutton,我以编程方式创建了一个ui视图,并添加了一个ui按钮,作为它的子视图。 我希望UIViewController成为该按钮操作的目标。 我该怎么做? 如果它是由Interface Builder创建的,那么使用iAction就很容易了。您可以将目标和操作添加到按钮 [button addTarget:controller/self action:@selector(onTapButton) forControlEvents:UIControlEventTouchUpInside]; 目标是控制器

我以编程方式创建了一个
ui视图
,并添加了一个
ui按钮
,作为它的子视图。
我希望
UIViewController
成为该按钮操作的目标。
我该怎么做?

如果它是由Interface Builder创建的,那么使用
iAction

就很容易了。您可以将目标和操作添加到按钮

[button addTarget:controller/self action:@selector(onTapButton) forControlEvents:UIControlEventTouchUpInside];
目标是控制器,所以若您想在当前控制器中处理触摸事件,请使用self。另一方面,您应该有一个指向控制器obj的指针/引用,并使用该引用而不是self。
onTapButton
是选择器,当用户点击按钮时将调用该选择器
onTapButton
不接受任何参数,如果要与参数一起使用,请使用
onTapButton:

- (IBAction/void)onTapButton{
}
-(IBAction/void)onTapButton:(id)sender{
}
注:
更好的方法是处理这个问题,就是使用委托模式,在self中有一个target,即什么样的类,然后调用delegate,控制器应该实现这个委托。保持对控制器的直接引用不是好的做法。

如果要以编程方式将按钮添加到UIView的子类中,则可以通过以下两种方式之一执行此操作:

  • 可以将按钮设置为视图的属性,然后在实例化视图的viewController中,可以按如下方式设置按钮的目标:

    [viewSubclass.buttonName addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
    
    这将把按钮的目标设置为一种buttonTapped方法:在viewController.m中

  • 可以在子视图中创建协议,父视图控制器将遵守该协议。在视图中,添加按钮时,将其设置为调用视图中的方法。然后从该视图调用委托方法,以便viewController可以响应该方法:

  • 在顶部视图子类.h中创建协议:

    @protocol ButtonProtocolName
    
    - (void)buttonWasPressed;
    
    @end
    
    @interface someViewController : UIViewController <SomeButtonProtocolName>
    
    为委托创建属性:

    @property (nonatomic, assign) id <ButtonProtocolName> delegate;
    
    SomeView *view = ... // Init your view
    // Set the delegate
    view.delegate = self;
    
    在buttonTapped:方法中,调用委托方法:

    - (void)buttonTapped:(id)sender {
        [self.delegate buttonWasPressed];
    }
    
    在viewController.h中,您需要确保它符合协议:

    @protocol ButtonProtocolName
    
    - (void)buttonWasPressed;
    
    @end
    
    @interface someViewController : UIViewController <SomeButtonProtocolName>
    
    最后,将委托方法按钮添加到viewController.m:

    - (void)buttonWasPressed {
        // Put code here for button's intended action.
    }
    
    更新以提供Swift示例

    // Simple delegate protocol.
    protocol SomeViewDelegate: class {
      // Method used to tell the delegate that the button was pressed in the subview.
      // You can add parameters here as you like.
      func buttonWasPressed()
    }
    
    class SomeView: UIView {
      // Define the view's delegate.
      weak var delegate: SomeViewDelegate?
    
      // Assuming you already have a button.
      var button: UIButton!
    
      // Once your view & button has been initialized, configure the button's target.
      func configureButton() {
        // Set your target
        self.button.addTarget(self, action: #selector(someButtonPressed(_:)), for: .touchUpInside)
      }
    
      @objc func someButtonPressed(_ sender: UIButton) {
        delegate?.buttonWasPressed()
      }
    }
    
    // Conform to the delegate protocol
    class SomeViewController: UIViewController, SomeViewDelegate {
      var someView: SomeView!
    
      func buttonWasPressed() {
        // UIViewController can handle SomeView's button press.
      }
    }
    
    此外,下面是一个使用闭包而不是委托的快速示例。(这种方法也可以使用块在ObjC中实现。)

    现在,如果您使用的是UINavigationController,则按钮按下功能将

    - (void)buttonPressed:(id)sender
    {
        NewViewController *newVC = [NewViewController new];
        [self.navigationController pushViewController:newVC animated:YES];
    
    }
    
    如果未使用导航控制器,则

    - (void)buttonPressed:(id)sender
    {
        NewViewController *newVC = [NewViewController new];
        [self presentViewController:newVC animated:YES completion:nil];
    
    }
    

    我们也可以在没有代表的情况下实现这一目标

    CustomUIView.m
    类中,实现以下方法:-

    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
    
        NSArray *viewsInNib = [[NSBundle mainBundle]loadNibNamed:@"AddressAlertView" owner:self options:nil];
        for (id view in viewsInNib) {
            if ([view isKindOfClass:[self class]]) {
                self = view;
                break;
            }
        }
    
        return self;
    }
    
    说明:-在initWithFrame方法中,我正在加载当前nib。加载nib意味着初始化它包含的所有子视图。获取同一类的完全初始化视图并分配给self。返回包含完全初始化的uiview的self

    viewcontroller.m
    文件中,编写以下代码以添加自定义uiview并设置按钮的目标:-

    UIWindow *mainWindow = [[[UIApplication sharedApplication]delegate]window];
    
    AddressAlertView *objAddressAlertView = [[AddressAlertView alloc] initWithFrame:mainWindow.bounds];
    [objAddressAlertView.btnCross addTarget:self
                                     action:@selector(dummy)
                           forControlEvents:UIControlEventTouchUpInside];
    if (objAddressAlertView)
        [mainWindow addSubview:objAddressAlertView];
    
    斯威夫特4号

    class MyView: UIView {
    
     weak var delegate: MyBtnDelegate?
    
     var myBtn: UIButton = {
        let myCustomButton = UIButton()
    
        // Button UI code goes here
    
        myCustomButton.addTarget(self, action: #selector(saveData), for: .touchUpInside)
        return myCustomButton
    }()
    
    
    @objc func saveData() {
    
    delegate?.doSomething()
    
    }
    
    在视图控制器中

    protocol MyBtnDelegate: class {
    func doSomething()
    }
    
    class ViewController: UIViewController, MyBtnDelegate {
    var customView = MyView()
    
     override func viewDidLoad() {
        super.viewDidLoad()
        customView.delegate = self  // Unless you add this line code won't be working
    }
    
    func doSomething() {
    
    //Do whatever you want
    
      }
    }
    

    希望这有帮助。快乐编码:

    代码,显示一些代码。使stackoverflowers更容易帮助您这行不通。OP正在视图的子类中添加按钮,因此self将是视图,而不是视图控制器。在这种情况下,他应该引用控制器并用视图控制器替换self。C_X:我知道您做出此响应已经几个月了,但我想指出,您的第二条评论实际上违反了MVC。视图本身不应代表viewController,因此在视图子类中使用对viewController的引用是个坏主意。最佳实践是实现委托,以便viewController在调用某个方法时可以为视图执行操作。(接受的答案中有一个例子。)感谢您的回答,我还应该如何将UITextField委派设置为UIViewController?如果视图中有UITextField,则可以使用与上面所示相同的方法进行设置。但是,如果使用选项2,则必须将视图子类设置为textfield委托,然后使用视图的委托将更改传达给viewController。在文本字段的情况下,使用选项1会更容易。这比需要的复杂得多。我在这里回答了一个类似的问题:@leftspin,依我看,你的链接应该被认为是一种不好的做法,因为它没有明确说明预期的行为应该是什么。当然,它减少了一些锅炉板代码,但模糊了实现。@Aroncittendon我的答案是简单地使用责任链模式(),它“促进松散耦合的思想,这被认为是编程的最佳实践”,并且是响应者链背后的核心思想。它不比使用NSNotifications、委托,甚至(在某种意义上)方法重载更模糊实现;所有这些都是间接的技术,以促进松散耦合。有关良好的讨论,请参阅
    protocol MyBtnDelegate: class {
    func doSomething()
    }
    
    class ViewController: UIViewController, MyBtnDelegate {
    var customView = MyView()
    
     override func viewDidLoad() {
        super.viewDidLoad()
        customView.delegate = self  // Unless you add this line code won't be working
    }
    
    func doSomething() {
    
    //Do whatever you want
    
      }
    }