UIBarButtonItem: цільова дія не працює?


80

У мене є власний вигляд усередині UIBarButtonItem, встановлений за допомогою виклику -initWithCustomView. Елемент моєї кнопки на панелі відображається нормально, але коли я натискаю його, він не викликає дії щодо мого цільового об'єкта.

Ось мій код:

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)];

Відповіді:


126

Я не думаю, що ціль та дії UIBarButtonItem стосуються власних подань. Спробуйте використовувати UIButton замість UIImageView і застосувати ціль та дію до кнопки.

Зразок коду в 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

31
Дякую. UIBarButtonItemуспадковує від UIBarItemі NSObjectтому не знає нічого про дотики. Було б непогано, якби в документах згадувалося, що властивості actionand targetзастосовуються лише в тому випадку, якщо спеціальний вигляд - це кнопка UIB.
Джейсон Мур,

18
@JasonMoore: ще краще, було б непогано, якби кнопки діяли як ... кнопки. Якщо він поводився так, як це очікує програміст, додаткова документація не потрібна.
Генерал Майк

Дуже дякую. Крім того, ми можемо використовувати посилання IBOutlet на setTarget та setAction у коді. Але якщо ми створимо UIBarButtonItem у коді, ми не можемо встановитиTarget та setAction, це не буде працювати.
MOBYTELAB

1
Хоча це стара публікація, я все одно хотів поділитися цим. Оскільки я втомився від необхідності звертати увагу на об’єкти UIBarButtonItem, які мають власні перегляди чи ні, я написав розширюючий клас, який насправді поводиться так, як мені здається. Ви можете знайти джерело тут: gist.github.com/tvervest/8708465
Thomas Vervest

хе, я використовував targetForAction замість target.
Mathijs Segers

24

У мене була та сама проблема, але я не хотів використовувати UIButtonзамість власного подання для мого UIBarButtonItem(за відповіддю drawnonward).

Крім того, ви можете додати a UIGestureRecognizerдо власного подання, перш ніж використовувати його для ініціалізації UIBarButtonItem; здається, це працює в моєму проекті.

Ось як я зміню ваш вихідний код:

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];

У мене нічого не працювало, лише це рішення. Спеціальний вигляд не дозволяє встановити дію. Звичайна кнопка UIB одночасно має проблеми з відображенням заднього зображення. З цим розпізнавачем жестів це нарешті вдалося.
Денис

додавання тапжестуру до мого користувацького подання не спрацювало, але воно спрацювало, коли я додав його до елемента кнопки на панелі.
Роналду1

@ Ronaldoh1 Як ви додали UITapgesture до UIBarButtonItem?
цуз

@ user013948 так само, як і для будь-якого перегляду. Підкласи UIBarButtonItem UIView (якщо я не помиляюсь).
Роналду1,


24

Ось як я змушую це працювати:

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

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

9

Ось як я реалізував UIButton усередині UIBarButtonItem:

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];

Це рішення є правильним. Ми можемо використовувати UIButton і для додавання іншого подання.
Хоробрий

7

У мене була подібна проблема. І я спочатку йшов шляхом, запропонованим @drawnonward, але потім зіткнувся з проблемою, коли намагався довести свою дію до контролера переходу на iPad: використання вбудованого UIButton як власного подання означає, що UIButton є відправником події, і контролер popover's currentPopoverFromBarButtonItem: метод аварійно завершує роботу, коли він намагається надіслати йому повідомлення, які відповідають лише фактичним UIBarButtonItems.

Врешті-решт я знайшов рішення викрасти зображення, яке я хотів використати (піктограма “інформація”), з викидного UIButton і побудувати мій UIBarButtonItem наступним чином:

// 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];

Використання цього ініціалізатора дає кнопку панелі, ціль і селектор якої насправді працюють. Це також простіше, ніж обтікання зображення у власному поданні, але це просто обмерзання.


1
Це вирішило це для мене! Для використання з popover використовуйте наступне: [myPopover presentPopoverFromBarButtonItem: sender permittedArrowDirections: UIPopoverArrowDirectionAny animated: YES];
mpemburn

2

Якщо ви не хочете розраховуватися з UIImage і маєте власний вигляд у вашому barbuttonitem, встановіть розпізнавач жестів натисканням на властивість customview вашого barbuttonitem

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


1

Джейкобе, все виглядає добре, проте, можливо, ти не вказав правильний селектор.

Чи можете ви підтвердити, що ваша дія фактично оголошена

- (void) deselectAll;

і ні

- (void) deselectAll:(id)sender;

Якщо це останнє, вам потрібно буде встановити дію @selector(deselectAll:). (зверніть увагу на крапку з комою, щоб вона відповідала декларації методу)

Крім того, може бути порожнеча IBAction, але це не має значення для цієї проблеми.


@ohhorob, я позитивно ставлюсь до підпису методу.
Jacob Relkin

@ohhorob, я також не використовую IB;)
Якоб Рєлкін

також переконайтесь, що екземпляр, який ви встановлюєте як ціль, не звільняється та не роздається. Це підклас контролера навігації чи інший контролер подання в навігаційній ієрархії?
ohhorob

@ohhorob, Цей код знаходиться в контролері перегляду, який не випускається.
Яків Рєлкін

як ви підтвердили, що вас deselectAllне викликають? Встановивши точку зупинки налагоджувача, або ви просто не бачите очікуваних результатів?
ohhorob

1

Свіфт 3. У мене була подібна проблема, коли я мав власний вигляд усередині елемента кнопки панелі. Для того, щоб натиснути на кран, я призначив подання жесту та встановив дію. Вигляд повинен був бути торговою точкою, щоб призначити йому. Роблячи це, він працював із користувацьким видом.

Встановлення жесту як змінної класу

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

In viewDidLoad

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

1

Swift 3 : Нижче наведено мою повну реалізацію налаштування кнопок та обробки подій.

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
}

Сподіваюся, це допомагає


0

Ваш власний вигляд їсть сенсорні події чи передає їх батьківському перегляду?


як бачите, мій власний вигляд - це просто звичай UIImageView. Отже, це не їсть ніяких подій, ні.
Jacob Relkin

0

Щоб полегшити роботу, я створив категорію на UIBarButtonItem, яка виглядає так:

@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

У вашому клієнтському коді просто використовуйте:

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

Зроблено таким чином, ви все ще можете підключити свої цілі та дії в IB (введення стільки конфігурації інтерфейсу в IB, скільки ви можете, - це добре).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.