2012-02-05 11 views
6

Với sự thiết lập sauIOS UIMenuController UIMenuItem, làm thế nào để xác định sản phẩm được chọn theo phương pháp chọn generic

.... 
MyUIMenuItem *someAction = [[MyUIMenuItem alloc]initWithTitle : @"Something" action : @selector(menuItemSelected:)]; 
MyUIMenuItem *someAction2 = [[MyUIMenuItem alloc]initWithTitle : @"Something2" action : @selector(menuItemSelected:)]; 
.... 

- (IBAction) menuItemSelected : (id) sender 
{ 
    UIMenuController *mmi = (UIMenuController*) sender; 
} 

Làm thế nào để tìm ra những đơn hàng đã được lựa chọn.

Và đừng nói rằng bạn cần phải có hai phương pháp ... Cảm ơn trước.

+0

Vì vậy, tôi đoán KHÔNG CÓ CÁCH để tạo các menu "mềm" trong IOS? – ort11

Trả lời

14

OK, tôi đã giải quyết vấn đề này. Giải pháp không phải là khá, và lựa chọn tốt hơn là "Apple sửa chữa vấn đề", nhưng điều này ít nhất là hoạt động.

Trước hết, hãy đặt tiền tố UIMenuItem bộ chọn hành động của bạn với "magic_". Và đừng tạo ra các phương thức tương ứng. (Nếu bạn có thể làm điều đó, sau đó bạn không cần giải pháp này anyway).

Tôi đang xây dựng tôi UIMenuItems như sau:

NSArray *buttons = [NSArray arrayWithObjects:@"some", @"random", @"stuff", nil]; 
NSMutableArray *menuItems = [NSMutableArray array]; 
for (NSString *buttonText in buttons) { 
    NSString *sel = [NSString stringWithFormat:@"magic_%@", buttonText]; 
    [menuItems addObject:[[UIMenuItem alloc] 
         initWithTitle:buttonText 
         action:NSSelectorFromString(sel)]]; 
} 
[UIMenuController sharedMenuController].menuItems = menuItems; 

Bây giờ lớp học của bạn mà bắt các thông điệp nút tap cần một vài bổ sung. (Trong trường hợp của tôi lớp là một lớp con của UITextField Yours có thể là cái gì khác..)

Đầu tiên, phương pháp mà tất cả chúng ta đã muốn có nhưng điều đó không tồn tại:

- (void)tappedMenuItem:(NSString *)buttonText { 
    NSLog(@"They tapped '%@'", buttonText); 
} 

Sau đó, các phương pháp mà làm cho nó có thể:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { 
    NSString *sel = NSStringFromSelector(action); 
    NSRange match = [sel rangeOfString:@"magic_"]; 
    if (match.location == 0) { 
     return YES; 
    } 
    return NO; 
} 

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { 
    if ([super methodSignatureForSelector:sel]) { 
     return [super methodSignatureForSelector:sel]; 
    } 
    return [super methodSignatureForSelector:@selector(tappedMenuItem:)]; 
} 

- (void)forwardInvocation:(NSInvocation *)invocation { 
    NSString *sel = NSStringFromSelector([invocation selector]); 
    NSRange match = [sel rangeOfString:@"magic_"]; 
    if (match.location == 0) { 
     [self tappedMenuItem:[sel substringFromIndex:6]]; 
    } else { 
     [super forwardInvocation:invocation]; 
    } 
} 
+4

Đây là triển khai đầy đủ với hỗ trợ chặn. https://github.com/steipete/PSMenuItem – steipete

+0

@steipete triển khai khối của bạn là thiên tài –

-1

ort11, bạn có thể muốn tạo thuộc tính của myuimenuitem và đặt một số loại Thẻ. Cách thay thế đối tượng của người gửi có thể được nhận ra bằng thẻ của nó. Trong Ibaction, bạn có thể thiết lập một câu lệnh switch có thể tương ứng với mỗi sender.tag và làm việc thông qua logic đó. Tôi đoán đó là cách đơn giản nhất để đi.

+0

Người gửi là Menu không phải là mục. Đây là lý do tại sao câu hỏi. Tại sao IOS sẽ làm điều này? Chỉ cần không thực hiện từ. – ort11

+0

ord11, bạn đang khởi tạo trình đơn với các tiêu đề "Tiêu đề" khác nhau, vậy tại sao bạn không thể kiểm tra tham chiếu của mình đối tượng với Tiêu đề là Caleb được đề xuất. Vì người gửi chỉ là loại id, bạn có thể kiểm tra loại Lớp cụ thể và sau đó kiểm tra "Tiêu đề" của nó, chống lại nó. Bằng cách đó bạn có thể tham chiếu đến loại lớp MyUIMenuItem. một cái gì đó như thế này. if ([sender isKindofClass: [MyUIMenuItem class]]) và sau đó một câu lệnh if if ([sender.title isEqualToString: @ "Something2"]) thì người gửi UIMenuController * mmi = (UIMenuController *); nơi người gửi của bạn là * someAction2 trong trường hợp này. Hy vọng điều này sẽ giúp – kforkarim

+0

Tên người gửi là Menu, không phải Menu Item – ort11

0

Người ta hy vọng rằng hành động được liên kết với một mục menu nhất định sẽ bao gồm thông số sender sẽ trỏ đến mục menu đã chọn. Sau đó, bạn có thể chỉ cần kiểm tra tiêu đề của mục, hoặc làm như kforkarim gợi ý và phân lớp UIMenuItem để bao gồm một proeprty mà bạn có thể sử dụng để xác định mục. Thật không may, theo số this SO question, thông số người gửi luôn là số không. Câu hỏi đó đã hơn một tuổi, vì vậy mọi thứ có thể đã thay đổi - hãy xem những gì bạn nhận được trong tham số đó.

Cách khác, có vẻ như bạn sẽ cần một hành động khác nhau cho từng mục menu. Tất nhiên, bạn có thể thiết lập nó để tất cả các hành động của bạn gọi một phương pháp phổ biến, và nếu tất cả họ làm điều gì đó rất giống nhau mà có thể có ý nghĩa.

+0

Cố gắng tạo một menu mềm. Thực hiện các hành động khác nhau là không thực tế cho việc này. Tham số không phải lúc nào cũng nil, nó là một menu. Tôi không thấy một cách để làm những gì bạn nói do đó, câu hỏi, cảm ơn. – ort11

0

Hóa ra nó có thể để có được những đối tượng UIButton (mà thực chất là UICalloutBarButton) đại diện cho UIMenuItem nếu bạn phân lớp UIApplication và reimplement -sendAction:to:from:forEvent:. Mặc dù chỉ có -flash chọn đi qua UIApplication, nó là đủ.

@interface MyApplication : UIApplication 
@end 

@implementation MyApplication 
- (BOOL)sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event 
{ 
    // target == sender condition is just an additional one 
    if (action == @selector(flash) && target == sender && [target isKindOfClass:NSClassFromString(@"UICalloutBarButton")]) { 
     NSLog(@"pressed menu item title: %@", [(UIButton *)target titleLabel].text); 
    } 
    return [super sendAction:action to:target from:sender forEvent:event]; 
} 
@end 

Bạn có thể lưu target (hoặc bất kỳ dữ liệu nào bạn cần từ nó), ví dụ: và truy cập nó sau này từ hành động của UIMenuItem của bạn.

Và để làm cho công việc lớp con UIApplication của bạn, bạn phải vượt qua tên của nó như là một tham số thứ ba để UIApplicationMain():

int main(int argc, char *argv[]) 
{ 
    @autoreleasepool { 
     return UIApplicationMain(argc, argv, NSStringFromClass([MyApplication class]), NSStringFromClass([YOUR_APP_DELEGATE class])); 
    } 
} 

Giải pháp này hoạt động trên iOS 5.x-7.0 như bưu ngày (không kiểm tra trên các phiên bản cũ hơn).