UIBarButtonItem: цель-действие не работает?


у меня есть пользовательский вид внутри 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)];
11 68

11 ответов:

Я не думаю, что цель и действие 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

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

кроме того, вы можете добавить 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];

вот как это работает:

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

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

вот как я реализовал 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];

У меня была похожая проблема. И я изначально пошел по пути предложенным @drawnonward, но потом начались проблемы, когда я пытался мои действия настоящего всплывающем окне контроллера на iPad: с помощью встроенного UIButton как пользовательское представление означает UIButton является отправителем событие, и пирог контроллера presentPopoverFromBarButtonItem: метод завершает работу при попытке отправить сообщения, которые подходят только к фактическим 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];

использование этого инициализатора дает кнопку панели, цель и селектор которой действительно работают. Это также проще, чем обернуть изображение в пользовательский вид, но это просто обледенение.

Джейкоб, все выглядит хорошо, однако вы не предоставили правильный селектор.

можете ли вы проверить, что ваше действие фактически объявлено

- (void) deselectAll;

, а не

- (void) deselectAll:(id)sender;

если это последнее, вам нужно будет установить действие в @selector(deselectAll:). (обратите внимание на точку с запятой, чтобы соответствовать объявлении метода)

кроме того, пустота может быть IBAction, но это не имеет отношения к этой проблеме.

ваш пользовательский вид ест сенсорные события или передает их в родительский вид?

чтобы сделать это легко работать, я создал категорию на 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 (нажатие столько UI config в IB, как вы можете это хорошо).

Swift 3. У меня была аналогичная проблема, когда у меня был пользовательский вид внутри элемента кнопки панели. Чтобы заставить кран работать, я назначил жест виду и установил действие. Представление должно было быть выходом, чтобы назначить его. При этом он работал с пользовательским представлением.

установка жеста в качестве переменной класса

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

в viewDidLoad

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

Если вы не хотите соглашаться с UIImage и иметь пользовательское представление в своем barbuttonitem, установите распознаватель жестов крана в свойство customview вашего barbuttonitem

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

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
}

надеюсь, что это помогает