UIBarButtonItem: Zielaktion funktioniert nicht?


79

Ich habe eine benutzerdefinierte Ansicht in einem UIBarButtonItem, die durch Aufrufen festgelegt wurde -initWithCustomView. Mein Balkenschaltflächenelement wird einwandfrei wiedergegeben, aber wenn ich darauf tippe, wird die Aktion für mein Zielobjekt nicht aufgerufen.

Hier ist mein Code:

UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"someImage.png"]];
UIBarButtonItem *bbItem = [[UIBarButtonItem alloc] initWithCustomView:imageView];
self.navigationItem.leftBarButtonItem = bbItem;
[imageView release];
[bbItem setTarget:self];
[bbItem setAction:@selector(deselectAll)];

Antworten:


124

Ich glaube nicht, dass das Ziel und die Aktion des UIBarButtonItem für benutzerdefinierte Ansichten gelten. Versuchen Sie, einen UIButton anstelle von UIImageView zu verwenden und das Ziel und die Aktion auf die Schaltfläche anzuwenden.

Beispielcode in Swift:

let button  = UIButton(type: .Custom)
if let image = UIImage(named:"icon-menu.png") {
    button.setImage(image, forState: .Normal)
}
button.frame = CGRectMake(0.0, 0.0, 30.0, 30.0)
button.addTarget(self, action: #selector(MyClass.myMethod), forControlEvents: .TouchUpInside)
let barButton = UIBarButtonItem(customView: button)
navigationItem.leftBarButtonItem = barButton

30
Vielen Dank. UIBarButtonItemerbt von UIBarItemund NSObjectweiß daher nichts über Berührungen. Es wäre schön, wenn in den Dokumenten erwähnt würde, dass die Eigenschaften actionund targetnur gelten, wenn die benutzerdefinierte Ansicht ein UIButton ist.
Jason Moore

18
@ JasonMoore: Besser noch, es wäre schön, wenn Knöpfe wie ... Knöpfe wirken würden. Wenn es sich so verhält, wie es ein Programmierer erwartet, ist die zusätzliche Dokumentation nicht erforderlich.
GeneralMike

Vielen Dank. Wir können auch IBOutlet-Verweise auf setTarget und setAction im Code verwenden. Wenn wir jedoch UIBarButtonItem im Code erstellen, können wir setTarget und setAction nicht festlegen, es funktioniert nicht.
MOBYTELAB

1
Obwohl dies ein alter Beitrag ist, wollte ich ihn trotzdem teilen. Als ich es leid wurde, auf UIBarButtonItem-Objekte mit benutzerdefinierten Ansichten achten zu müssen oder nicht, schrieb ich eine erweiterte Klasse, die sich tatsächlich so verhält, wie sie sollte (glaube ich). Sie finden die Quelle hier: gist.github.com/tvervest/8708465
Thomas Vervest

heh, ich habe targetForAction anstelle von target verwendet.
Mathijs Segers

24

Ich hatte das gleiche Problem, war aber abgeneigt, eine UIButtonanstelle einer benutzerdefinierten Ansicht für meine zu verwenden UIBarButtonItem(gemäß der Antwort von Drawonward).

Alternativ können Sie UIGestureRecognizerder benutzerdefinierten Ansicht ein hinzufügen , bevor Sie sie zum Initialisieren verwenden UIBarButtonItem. Dies scheint in meinem Projekt zu funktionieren.

So würde ich Ihren ursprünglichen Code ändern:

UIImageView *SOCImageView = [[UIImageView alloc] initWithImage:
                             [UIImage imageNamed:@"cancel_wide.png"]];

UITapGestureRecognizer *tapGesture = 
       [[UITapGestureRecognizer alloc] initWithTarget:self 
                                               action:@selector(deselectAll:)];
[SOCImageView addGestureRecognizer:tapGesture];

SOItem.leftBarButtonItem = 
       [[[UIBarButtonItem alloc] initWithCustomView:SOCImageView] autorelease];
[tapGesture release];
[SOCImageView release];

Bei mir hat nichts funktioniert, nur diese Lösung. In der benutzerdefinierten Ansicht kann die Aktion nicht festgelegt werden. Gleichzeitig hat der einfache UIButton Probleme, das Hintergrundbild anzuzeigen. Mit diesem Gestenerkenner hat es endlich geklappt.
Denis

Das Hinzufügen der Tapgesture zu meiner benutzerdefinierten Ansicht hat nicht funktioniert, aber es hat funktioniert, als ich sie meinem Balkenschaltflächenelement hinzugefügt habe.
Ronaldoh1

@ Ronaldoh1 Wie haben Sie UITapgesture zu UIBarButtonItem hinzugefügt?
Tsuz

@ user013948 genau wie bei jeder ansicht. UIBarButtonItem-Unterklassen UIView (wenn ich mich nicht irre).
Ronaldoh1


24

So mache ich es:

UIButton* infoButton = [UIButton buttonWithType: UIButtonTypeInfoLight];
[infoButton addTarget:self action:@selector(displayAboutUs) forControlEvents:UIControlEventTouchDown];

UIBarButtonItem* itemAboutUs =[[UIBarButtonItem alloc]initWithCustomView:infoButton];
…

9

So habe ich den UIButton im UIBarButtonItem implementiert:

UIButton *logoButton = [UIButton buttonWithType:UIButtonTypeCustom];
[logoButton setImage: [UIImage imageNamed:@"icon.png"] forState:UIControlStateNormal];
logoButton.frame = CGRectMake(0, 0, 30, 30);
[logoButton addTarget:self action:@selector(showAbout:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithCustomView:logoButton];
self.navigationItem.rightBarButtonItem = barItem;
[barItem release];

Diese Lösung ist richtig. Wir können UIButton auch verwenden, um eine weitere Ansicht hinzuzufügen.
Mutig

7

Ich hatte ein ähnliches Problem. Ich folgte zunächst dem von @drawnonward vorgeschlagenen Pfad, geriet dann jedoch in Schwierigkeiten, als ich versuchte, meine Aktion als Popover-Controller auf einem iPad anzuzeigen: Die Verwendung eines eingebetteten UIButton als benutzerdefinierte Ansicht bedeutet, dass der UIButton der Absender des Ereignisses ist, und Die Methode presentPopoverFromBarButtonItem: des Popover-Controllers stürzt ab, wenn versucht wird, Nachrichten zu senden, die nur für tatsächliche UIBarButtonItems geeignet sind.

Die Lösung, die ich schließlich fand, bestand darin, das Bild, das ich verwenden wollte (das "Info" -Symbol), von einem Wegwerf-UIButton zu stehlen und mein UIBarButtonItem wie folgt zu erstellen:

// Make the info button use the standard icon and hook it up to work
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
UIBarButtonItem *barButton = [[[UIBarButtonItem alloc]        
      initWithImage:infoButton.currentImage
              style:UIBarButtonItemStyleBordered
             target:self
             action:@selector(showInfo:)] autorelease];

Die Verwendung dieses Initialisierers ergibt eine Balkenschaltfläche, deren Ziel und Auswahl tatsächlich funktionieren. Es ist auch einfacher als das Bild in eine benutzerdefinierte Ansicht zu verpacken, aber das ist nur ein Sahnehäubchen.


1
Das hat es für mich gelöst! Verwenden Sie zur Verwendung mit einem Popover Folgendes: [myPopover presentPopoverFromBarButtonItem: Absender erlaubtArrowDirections: UIPopoverArrowDirectionAny animiert: YES];
mpemburn

1

Jacob, alles sieht gut aus, aber Sie haben möglicherweise nicht den richtigen Selektor bereitgestellt.

Können Sie überprüfen, ob Ihre Aktion tatsächlich deklariert ist?

- (void) deselectAll;

und nicht

- (void) deselectAll:(id)sender;

Wenn es das letztere ist, müssen Sie die Aktion auf einstellen @selector(deselectAll:). (Beachten Sie das Semikolon, das mit der Methodendeklaration übereinstimmt.)

Möglicherweise ist dies auch nichtig IBAction, aber das ist für dieses Problem, das Sie haben, nicht relevant.


@ohhorob, ich bin positiv über die Methodensignatur.
Jacob Relkin

@ohhorob, ich benutze auch nicht IB;)
Jacob Relkin

Überprüfen Sie auch, ob die Instanz, die Sie als Ziel festlegen, nicht freigegeben und freigegeben wird. Handelt es sich um eine Navigationscontroller-Unterklasse oder eine andere Ansichtssteuerung in der Navigationshierarchie?
Ohhorob

@ohhorob, Dieser Code befindet sich in einem View Controller, der nicht freigegeben wird.
Jacob Relkin

Wie haben Sie bestätigt, dass deselectAllnicht angerufen wird? Wenn Sie einen Debugger-Haltepunkt festlegen, oder sehen Sie die erwarteten Ergebnisse einfach nicht?
Ohhorob

1

Swift 3. Ich hatte ein ähnliches Problem, bei dem ich eine benutzerdefinierte Ansicht innerhalb des Balkenschaltflächenelements hatte. Damit der Wasserhahn funktioniert, habe ich der Ansicht eine Geste zugewiesen und die Aktion festgelegt. Die Ansicht musste eine Steckdose sein, um sie zuzuweisen. Dabei funktionierte es mit der benutzerdefinierten Ansicht.

Festlegen der Geste als Klassenvariable

@IBOutlet weak var incidentView: UIView!
let incidentTap = UITapGestureRecognizer()

In viewDidLoad

incidentTap.addTarget(self, action: #selector(self.changeIncidentBarItem))
incidentView.addGestureRecognizer(incidentTap)

1

Wenn Sie sich nicht mit einem UIImage zufrieden geben möchten und eine benutzerdefinierte Ansicht in Ihrem Barbuttonitem haben möchten, setzen Sie einen Tippgestenerkenner auf die Eigenschaft customview Ihres Barbuttonitems

let tap = UITapGestureRecognizer(target: self, action: #selector(goProButtonPressed)) deviceStatusBarButtonItem.customView?.addGestureRecognizer(tap)


1

Swift 3 : Nachfolgend finden Sie meine vollständige Implementierung für die Anpassung von Schaltflächen und die Ereignisbehandlung.

override func viewDidLoad() {
    super.viewDidLoad()

    let button = UIButton.init(type: .custom)
    button.setTitle("Tester", for: .normal)
    button.setTitleColor(.darkGray, for: .normal)
    button.layer.borderWidth = 1
    button.layer.cornerRadius = 5
    button.layer.borderColor = UIColor.darkGray.cgColor
    button.addTarget(self, action: #selector(self.handleButton), for: .touchUpInside)

    self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    if let button = self.navigationItem.rightBarButtonItem?.customView {
        button.frame = CGRect(x:0, y:0, width:80, height:34)
    }
}

func handleButton( sender : UIButton ) {
    // It would be nice is isEnabled worked...
    sender.alpha = sender.alpha == 1.0 ? 0.5 : 1.0
}

Hoffe das hilft


0

Isst Ihre benutzerdefinierte Ansicht Berührungsereignisse oder gibt sie diese an die übergeordnete Ansicht weiter?


Wie Sie sehen können, ist meine benutzerdefinierte Ansicht nur eine einfache alte UIImageView. Es isst also keine Ereignisse, nein.
Jacob Relkin

0

Um die Arbeit zu vereinfachen, habe ich auf UIBarButtonItem eine Kategorie erstellt, die folgendermaßen aussieht:

@implementation UIBarButtonItem (CustomButtonView)

- (void)setButtonImage:(UIImage *)image
{
    UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setBackgroundImage:image forState:UIControlStateNormal];
    [button sizeToFit];
    [button addTarget:self.target action:self.action forControlEvents:UIControlEventTouchUpInside];
    self.customView = button;
}

- (UIImage *)buttonImage
{
    return [(UIButton *)self.customView imageForState:UIControlStateNormal];
}

@end

Verwenden Sie in Ihrem Client-Code einfach:

myBarButtonItem.buttonImage = [UIImage imagedNamed:@"image_name"];

Auf diese Weise können Sie Ihre Ziele und Aktionen weiterhin in IB verknüpfen (es ist eine gute Sache, so viel UI-Konfiguration wie möglich in IB zu übertragen).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.