如何让UIMenuController为自定义视图工作?

时间:2009-07-18 02:58:49

标签: iphone cocoa-touch iphone-sdk-3.0 uimenucontroller

我正在尝试使用以下代码:

UIMenuController * menu = [UIMenuController sharedMenuController];
[menu setTargetRect: CGRectMake(100, 100, 100, 100) inView: self.view];
[menu setMenuVisible: YES animated: YES];

菜单实例已准备就绪,但未显示 - 宽度始终为零。

或者这个UIPasteboard/UIMenuController主题是否有一些示例代码?

9 个答案:

答案 0 :(得分:49)

即使我读完你所有的答案,我也无法使它工作。我正在提供适用于所有人的现成代码。

假设我们有一个名为Controller的控制器类。您只需将以下代码粘贴到此控制器即可使菜单处于其视图中:


- (void)loadView {
    [super loadView];

    UILongPressGestureRecognizer *gr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
    [self.view addGestureRecognizer:gr];    
}

- (void) longPress:(UILongPressGestureRecognizer *) gestureRecognizer {
    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan) {
        CGPoint location = [gestureRecognizer locationInView:[gestureRecognizer view]];
        UIMenuController *menuController = [UIMenuController sharedMenuController];
        UIMenuItem *resetMenuItem = [[UIMenuItem alloc] initWithTitle:@"Item" action:@selector(menuItemClicked:)];

        NSAssert([self becomeFirstResponder], @"Sorry, UIMenuController will not work with %@ since it cannot become first responder", self);
        [menuController setMenuItems:[NSArray arrayWithObject:resetMenuItem]];
        [menuController setTargetRect:CGRectMake(location.x, location.y, 0.0f, 0.0f) inView:[gestureRecognizer view]];
        [menuController setMenuVisible:YES animated:YES];
    }
}

- (void) copy:(id) sender {
    // called when copy clicked in menu
}

- (void) menuItemClicked:(id) sender {
    // called when Item clicked in menu
}

- (BOOL) canPerformAction:(SEL)selector withSender:(id) sender {
    if (selector == @selector(menuItemClicked:) || selector == @selector(copy:)) {
        return YES;
    }
    return NO;
}

- (BOOL) canBecomeFirstResponder {
    return YES;
}

为了使菜单工作,必须做的是firstResponder(在我们的例子中我们的控制器 - 见[self becomeFirstResponder]行)必须能够成为第一响应者(覆盖方法canBecomeFirstResponder导致默认实现返回NO )以及- (BOOL) canPerformAction:(SEL)selector withSender:(id) sender应该对firstResponder

可以执行的任何操作返回YES

答案 1 :(得分:7)

如果您正在实现自定义视图并且该视图应该是响应者(而不是其他视图,如UITextField),则需要在视图中覆盖canBecomeFirstResponder函数并返回YES:

- (BOOL)canBecomeFirstResponder {
    return YES;
}

然后,当您显示菜单时,您应该执行以下操作:

- (void)myMenuFunc {
    if (![self becomeFirstResponder]) {
        NSLog(@"couldn't become first responder");
        return;
    }

    UIMenuController *theMenu = [UIMenuController sharedMenuController];
    CGRect selectionRect = CGRectMake(0, 0, 0, 0);
    [theMenu setTargetRect:selectionRect inView:self];
    [theMenu setMenuVisible:YES animated:YES];
}

答案 2 :(得分:6)

如果有人仍然有问题:我的菜单曾经工作,有一天奇迹般地停止工作。我的应用程序中的其他所有内容仍然可用现在我已经从[window makeKeyAndVisible]方法移除了application:didFinishLaunchingWithOptions:方法,虽然其他一切仍然有用,但这会中断UIMenuController

我身边的愚蠢错误,很难找到罪魁祸首......

答案 3 :(得分:4)

要显示UIMenuController,必须添加以下内容

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    if (action == @selector(cut:))
        return NO;
    else if (action == @selector(copy:))
        return YES;
    else if (action == @selector(paste:))
        return NO;
    else if (action == @selector(select:) || action == @selector(selectAll:))
        return NO;
    else
        return [super canPerformAction:action withSender:sender];
}

答案 4 :(得分:2)

我认为Cam是对的,需要覆盖canPerformAction和canBecomeFirstResponder

- (BOOL) canPerformAction:(SEL)action withSender:(id)sender
{
    if (action == @selector(doSomething:)) {
        return YES;
    }
    return NO;
}

- (BOOL)canBecomeFirstResponder {
    return YES;
}

答案 5 :(得分:1)

// MyView.h

@interface MyView : UIView {
    IBOutlet UITextField * textField_;
}

@end

// MyView.m

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    NSLog(@"show menu");

    [textField_ becomeFirstResponder];
    // [self.window becomeFirstResponder];

    UIMenuController * menu = [UIMenuController sharedMenuController];
    [menu setTargetRect: CGRectMake(0, 0, 100, 10) inView: self];
    [menu setMenuVisible: YES animated: YES];

    NSLog(@"menu width %f, visible %d", menu.menuFrame.size.width, menu.menuVisible);
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender{
    return YES;
}

您需要在canPerformAction中添加更多代码:withSender: - 它应该检查粘贴板和您的选择状态。 Apple的iPhone应用程序编程指南提供了几个代码片段。

答案 6 :(得分:0)

您不必将UIMenuController* menu添加到主视图或子视图中,即E.G。 self.view? 我认为它类似于[self.view addSubView:menu.view];或者我错过了你的问题。您可能还想设置菜单视图的框架。

答案 7 :(得分:0)

UIMenuController没有视图。我刚从apple的iPhone Application Programming Guide: Event Handling搜索了一些代码:

  

清单3-4显示编辑菜单

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *theTouch = [touches anyObject];

    if ([theTouch tapCount] == 2  && [self becomeFirstResponder]) {

        // selection management code goes here...

        // bring up editing menu.
        UIMenuController *theMenu = [UIMenuController sharedMenuController];
        CGRect selectionRect = CGRectMake(currentSelection.x, currentSelection.y, SIDE, SIDE);
        [theMenu setTargetRect:selectionRect inView:self];
        [theMenu setMenuVisible:YES animated:YES];
    }
}

答案 8 :(得分:0)

我是按照以下方式做到的。在init中经过很短的延迟后,只需调用显示菜单的方法。我不想从View Controller中调用它,也没有找到表示我的自定义视图出现的事件,我已准备好显示菜单。从我的角度来看,这样就行了。延迟可以更少,但由你决定。

@implementation DTSignatureImageView

- (id)initWithImage:(UIImage *)image
{
    self = [super initWithImage:image];
    if(self){
        self.contentMode = UIViewContentModeScaleAspectFit;
        self.frame = CGRectMake(0, 0, image.size.width / 2.5, image.size.height / 2.5);
        self.userInteractionEnabled = YES;

        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(signatureDidPan:)];
        [self addGestureRecognizer:pan];

        [self becomeFirstResponder];

        [self performSelector:@selector(showMenu) withObject:nil afterDelay:0.5];
    }

    return self;
}

- (BOOL)canBecomeFirstResponder
{
    return YES;
}

- (void)showMenu
{
    UIMenuController *menu = [UIMenuController sharedMenuController];
    menu.menuItems = @[
       [[UIMenuItem alloc] initWithTitle:@"Apply" action:@selector(applySignature)],
       [[UIMenuItem alloc] initWithTitle:@"Update" action:@selector(updateSignature)],
       [[UIMenuItem alloc] initWithTitle:@"Clear" action:@selector(delegateSignature)]];
    [menu setTargetRect:self.bounds inView:self];
    [menu setMenuVisible:YES animated:YES];
}

- (NSArray *)menuActions
{
    static NSArray *actions = nil;
    if (actions == nil){
        actions = @[
                    NSStringFromSelector(@selector(applySignature)),
                    NSStringFromSelector(@selector(updateSignature)),
                    NSStringFromSelector(@selector(delegateSignature))];
    }

    return actions;
}

- (void) signatureDidPan: (UIPanGestureRecognizer *)gesture
{
    switch (gesture.state) {
        case UIGestureRecognizerStateBegan: {
            [[UIMenuController sharedMenuController] setMenuVisible:NO animated:YES];
            break;
        }

        case UIGestureRecognizerStateEnded: {
            [self becomeFirstResponder];
            [self showMenu];
        }

        default:
            break;
    }

    CGPoint point = [gesture locationInView:gesture.view.superview];
    gesture.view.center = point;
}