UIBarButtonItem: target-action không hoạt động?


80

Tôi có một chế độ xem tùy chỉnh bên trong một UIBarButtonItem, được thiết lập bằng cách gọi -initWithCustomView. Mục nút thanh của tôi hiển thị tốt, nhưng khi tôi nhấn vào nó, nó không thực hiện hành động trên đối tượng mục tiêu của tôi.

Đây là mã của tôi:

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

Câu trả lời:


126

Tôi không nghĩ rằng mục tiêu và hành động của UIBarButtonItem áp dụng cho các chế độ xem tùy chỉnh. Hãy thử sử dụng UIButton thay vì UIImageView và áp dụng mục tiêu và hành động cho nút.

Mã mẫu trong 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
Cảm ơn. UIBarButtonItemkế thừa từ UIBarItemNSObjectvì vậy nó không biết bất cứ điều gì về cảm ứng. Sẽ rất tuyệt nếu các tài liệu đề cập rằng các thuộc tính actiontargetchỉ áp dụng nếu chế độ xem tùy chỉnh là UIButton.
Jason Moore

18
@JasonMoore: tốt hơn hết, sẽ rất tuyệt nếu các nút hoạt động giống như ... nút. Nếu nó hoạt động theo cách mà lập trình viên mong đợi, thì không cần tài liệu bổ sung.
GeneralMike 17/12/12

Cám ơn rất nhiều. Ngoài ra, chúng ta có thể sử dụng tham chiếu IBOutlet để setTarget và setAction trong mã. Nhưng nếu chúng ta tạo UIBarButtonItem trong mã, chúng ta không thể setTarget và setAction, nó sẽ không hoạt động.
MOBYTELAB

1
Mặc dù đây là một bài viết cũ nhưng dù sao tôi cũng muốn chia sẻ điều này. Khi tôi cảm thấy mệt mỏi khi phải chú ý đến các đối tượng UIBarButtonItem có chế độ xem tùy chỉnh hay không, tôi đã viết một lớp mở rộng thực sự hoạt động theo cách (tôi nghĩ) nó nên làm. Bạn có thể tìm nguồn tại đây: gist.github.com/tvervest/8708465
Thomas Vervest

heh, tôi đã sử dụng targetForAction thay vì target.
Mathijs Segers

24

Tôi đã gặp vấn đề tương tự, nhưng không thích sử dụng UIButtonchế độ xem thay vì chế độ xem tùy chỉnh cho UIBarButtonItem(theo phản hồi của drawnonward).

Ngoài ra, bạn có thể thêm a UIGestureRecognizervào dạng xem tùy chỉnh trước khi sử dụng nó để khởi tạo UIBarButtonItem; điều này dường như hoạt động trong dự án của tôi.

Đây là cách tôi sẽ sửa đổi mã gốc của bạn:

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

Không có gì làm việc cho tôi, chỉ có giải pháp này. Chế độ xem tùy chỉnh không cho phép thiết lập hành động. Đồng thời, Plain UIButton đang gặp sự cố khi hiển thị hình ảnh back ground. Với trình nhận dạng cử chỉ này, nó cuối cùng đã hoạt động.
Denis

thêm tấm thảm vào chế độ xem tùy chỉnh của tôi không hoạt động, nhưng nó đã hoạt động khi tôi thêm nó vào mục nút thanh của mình.
Ronaldoh1

@ Ronaldoh1 Bạn đã thêm UITapgesture vào UIBarButtonItem như thế nào?
tsuz

@ user013948 giống như bạn muốn xem bất kỳ chế độ xem nào. UIBarButtonItem phân lớp UIView (nếu tôi không nhầm lẫn).
Ronaldoh1


24

Đây là cách tôi làm cho nó hoạt động:

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

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

9

Đây là cách tôi triển khai UIButton bên trong 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];

Giải pháp này là chính xác. Chúng ta cũng có thể sử dụng UIButton để thêm một chế độ xem khác.
Brave,

7

Tôi đã có một vấn đề tương tự. Và ban đầu tôi đi theo con đường do @drawnonward đề xuất, nhưng sau đó gặp rắc rối khi cố gắng để hành động của mình hiển thị bộ điều khiển bật lên trên iPad: Sử dụng UIButton được nhúng làm chế độ xem tùy chỉnh có nghĩa là UIButton là người gửi sự kiện và phương thức presentPopoverFromBarButtonItem của trình điều khiển popover: bị treo khi nó cố gắng gửi cho nó các thông báo chỉ thích hợp với UIBarButtonItems thực tế.

Giải pháp cuối cùng tôi tìm thấy là lấy cắp hình ảnh tôi muốn sử dụng (biểu tượng “thông tin”) từ một UIButton bỏ đi và xây dựng UIBarButtonItem của tôi như sau:

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

Sử dụng trình khởi tạo này sẽ tạo ra một nút thanh có mục tiêu và bộ chọn thực sự hoạt động. Nó cũng dễ dàng hơn so với gói hình ảnh trong một chế độ xem tùy chỉnh, nhưng đó chỉ là đóng băng.


1
Điều này đã giải quyết nó cho tôi! Để sử dụng với cửa sổ bật lên, hãy sử dụng cái này: [myPopover presentPopoverFromBarButtonItem: sender allowArrowDirections: UIPopoverArrowDirectionAny animation: YES];
mpemburn

2

Nếu bạn không muốn giải quyết bằng UIImage và có chế độ xem tùy chỉnh trong barbuttonitem của mình, hãy đặt trình nhận dạng cử chỉ chạm vào thuộc tính customview của barbuttonitem

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


1

Jacob, mọi thứ có vẻ ổn, tuy nhiên bạn có thể chưa cung cấp bộ chọn chính xác.

Bạn có thể xác minh rằng hành động của bạn thực sự được khai báo không

- (void) deselectAll;

và không

- (void) deselectAll:(id)sender;

Nếu là sau này, bạn sẽ cần đặt hành động thành @selector(deselectAll:). (lưu ý dấu chấm phẩy để khớp với khai báo phương thức)

Ngoài ra, khoảng trống có thể có IBAction, nhưng điều đó không liên quan đến vấn đề bạn đang gặp phải.


@ohhorob, tôi tích cực về chữ ký phương pháp.
Jacob Relkin

@ohhorob, tôi cũng không sử dụng IB;)
Jacob Relkin

cũng kiểm tra xem trường hợp bạn đang đặt làm mục tiêu không được phát hành & dealloc'ed. Nó là một lớp con của bộ điều khiển điều hướng hay một bộ điều khiển chế độ xem khác trong hệ thống phân cấp điều hướng?
ohhorob

@ohhorob, Mã này nằm trong bộ điều khiển chế độ xem không được phát hành.
Jacob Relkin

Làm thế nào bạn xác nhận deselectAlllà không được gọi? Bằng cách đặt điểm ngắt của trình gỡ lỗi, hay bạn không thấy kết quả mong đợi?
ohhorob

1

Swift 3. Tôi đã gặp sự cố tương tự trong đó tôi có chế độ xem tùy chỉnh bên trong mục nút thanh. Để thao tác nhấn, tôi đã gán một cử chỉ cho chế độ xem và đặt hành động. Chế độ xem cần thiết để trở thành một lối thoát để gán cho nó. Làm điều này nó hoạt động với chế độ xem tùy chỉnh.

Đặt cử chỉ làm biến lớp

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

Trong viewDidLoad

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

1

Swift 3 : Dưới đây là cách triển khai đầy đủ của tôi để tùy chỉnh nút và xử lý sự kiện.

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
}

Hi vọng điêu nay co ich


0

Chế độ xem tùy chỉnh của bạn có ăn các sự kiện chạm hay chuyển chúng cho chế độ xem của cha mẹ không?


như bạn có thể thấy, chế độ xem tùy chỉnh của tôi chỉ là một cách đơn giản UIImageView. Vì vậy, nó không ăn bất kỳ sự kiện nào, không.
Jacob Relkin

0

Để làm cho điều này dễ dàng làm việc, tôi đã tạo một danh mục trên UIBarButtonItem trông giống như sau:

@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

Trong mã khách hàng của bạn, chỉ cần sử dụng:

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

Thực hiện theo cách này, bạn vẫn có thể kết nối các mục tiêu và hành động của mình trong IB (đẩy càng nhiều cấu hình UI vào IB càng tốt sẽ là Điều tốt).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.