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.