iPad撤消按钮(a-la Keynote和其他应用程序)

时间:2012-03-21 05:19:44

标签: ios ipad

在Keynote(以及其他应用程序)中,我注意到执行撤消/重做的“标准”界面是通过在工具栏上提供撤消按钮。

单击按钮(始终启用)取消最近的操作。 (如果没有最近的撤消操作,它将显示撤消/重做菜单。)

长按“撤消”按钮可打开“撤消/重做”菜单。

我搜索了实现此方法的方法,到目前为止我找到的最佳答案是following link

我想知道是否有人知道更简单的方法?

谢谢!

4 个答案:

答案 0 :(得分:4)

在审查了所有方法并与朋友讨论之后,下面是我使用的解决方案,对于UIBarButtonItem,它响应两个点击并长按(TapOrLongPressBarButtonItem)。

它基于以下原则:

  1. 子类UIBarButtonItem
  2. 使用自定义视图(因此处理长按非常简单 - 因为我们的自定义视图对长按手势处理程序没有问题...)
  3. ...到目前为止 - 这种方法是在other SO thread - 我不喜欢这种方法,因为我找不到足够简单的方法使自定义视图看起来像iPad导航栏按钮...... Soooo ......

    使用Water Lou的UIGlossyButton(感谢水!)。这个用法封装在子类中......

    结果代码如下:

    @protocol TapOrPressButtonDelegate;
    @interface TapOrPressBarButtonItem : UIBarButtonItem {  
        UIGlossyButton* _tapOrPressButton;
        __weak id<TapOrPressButtonDelegate> _delegate;
    }
    - (id)initWithTitle:(NSString*)title andDelegate:(id<TapOrPressButtonDelegate>)delegate;
    @end
    
    @protocol TapOrPressButtonDelegate<NSObject>
    - (void)buttonTapped:(UIButton*)button withBarButtonItem:(UIBarButtonItem*)barButtonItem;
    - (void)buttonLongPressed:(UIButton*)button withBarButtonItem:(UIBarButtonItem*)barButtonItem;
    @end
    
    @implementation TapOrPressBarButtonItem
    - (void)buttonLongPressed:(UILongPressGestureRecognizer*)gesture {
        if (gesture.state != UIGestureRecognizerStateBegan)
            return;
        if([_delegate respondsToSelector:@selector(buttonLongPressed:withBarButtonItem:)]) {
            [_delegate buttonLongPressed:_tapOrPressButton withBarButtonItem:self];
        }
    }
    
    - (void)buttonTapped:(id)sender {
        if (sender != _tapOrPressButton) {
            return;
        }
    
        if([_delegate respondsToSelector:@selector(buttonTapped:withBarButtonItem:)]) {
            [_delegate buttonTapped:_tapOrPressButton withBarButtonItem:self];
        }   
    }
    
    - (id)initWithTitle:(NSString*)title andDelegate:(id<TapOrPressButtonDelegate>)delegate {
        if (self = [super init]) {
            // Store delegate reference
            _delegate = delegate;
    
            // Create the customm button that will have the iPad-nav-bar-default appearance 
            _tapOrPressButton = [UIGlossyButton buttonWithType:UIButtonTypeCustom];
            [_tapOrPressButton setTitle:title forState:UIControlStateNormal];
            [_tapOrPressButton setNavigationButtonWithColor:[UIColor colorWithRed:123.0/255 green:130.0/255 blue:139.0/255 alpha:1.0]];
            // Calculate width...
            CGSize labelSize = CGSizeMake(1000, 30);
            labelSize = [title sizeWithFont:_tapOrPressButton.titleLabel.font constrainedToSize:labelSize lineBreakMode:UILineBreakModeMiddleTruncation];
            _tapOrPressButton.frame = CGRectMake(0, 0, labelSize.width+20, 30);
    
            // Add a handler for a tap
            [_tapOrPressButton addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
            // Add a handler for a long-press
            UILongPressGestureRecognizer* buttonLongPress_ = [[UILongPressGestureRecognizer alloc] initWithTarget:self
                                                                                                           action:@selector(buttonLongPressed:)];
            [_tapOrPressButton addGestureRecognizer:buttonLongPress_];
    
            // Set this button as the custom view of the bar item...
            self.customView = _tapOrPressButton;
        }
        return self;
    }
    
    // Safe guards...
    - (id)initWithImage:(UIImage *)image style:(UIBarButtonItemStyle)style target:(id)target action:(SEL)action {
        NSLog(@"%s not supported!", __FUNCTION__);
        return nil;
    }
    
    - (id)initWithImage:(UIImage *)image landscapeImagePhone:(UIImage *)landscapeImagePhone style:(UIBarButtonItemStyle)style target:(id)target action:(SEL)action {
        NSLog(@"%s not supported!", __FUNCTION__);
        return nil;
    }
    
    - (id)initWithTitle:(NSString *)title style:(UIBarButtonItemStyle)style target:(id)target action:(SEL)action {
        NSLog(@"%s not supported!", __FUNCTION__);
        return nil;
    }
    - (id)initWithBarButtonSystemItem:(UIBarButtonSystemItem)systemItem target:(id)target action:(SEL)action {
        NSLog(@"%s not supported!", __FUNCTION__);
        return nil;
    }
    
    - (id)initWithCustomView:(UIView *)customView {
        NSLog(@"%s not supported!", __FUNCTION__);
        return nil;
    }
    
    @end
    

    您需要做的就是:

    <强> 1。实例化如下:

    TapOrPressBarButtonItem* undoMenuButton = [[TapOrPressBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Undo", @"Undo Menu Title") andDelegate:self];

    <强> 2。将按钮连接到导航栏:

    [self.navigationItem setLeftBarButtonItem:undoMenuButton animated:NO];

    第3。实现TapOrPressButtonDelegate协议,你就完成了......

    -(void)buttonTapped:(UIButton*)button withBarButtonItem:(UIBarButtonItem*)barButtonItem {
        [self menuItemUndo:barButtonItem];
    }
    
    -(void)buttonLongPressed:(UIButton*)button withBarButtonItem:(UIBarButtonItem*)barButtonItem {
        [self undoMenuClicked:barButtonItem];
    }

    希望这有助于其他任何人......

答案 1 :(得分:0)

如果您正在使用IB(或者在Xcode4中使用设计器......我猜它被称为),那么您可以选择&#34;撤消&#34;从第一个响应者并将该操作拖动到一个按钮。如果不能覆盖它,我可以给你更具体的说明。

这里看起来像Undo Interface Builder image

它在列的左下方&#34;已接收的操作&#34;在底部

答案 2 :(得分:0)

我相信密钥实际上是在UINavigationBar本身。与UIButton或其他普通触摸跟踪对象不同,我怀疑UIBarItems不会处理他们自己的触摸。它们不继承UIResponder或UIControl方法。但是UINavigationBar当然可以。我个人已经多次直接向UINavigationBar添加手势。

我建议您覆盖UINavigationBar子类中的触摸处理,并检查其子项的触摸。如果孩子是你的特殊撤销按钮,你可以相应地处理它。

答案 3 :(得分:0)

UIButton* undoButton = [UIButton buttonWithType:UIButtonTypeCustom];
[undoButton addTarget:self action:@selector(undoPressStart:) forControlEvents:UIControlEventTouchDown];
[undoButton addTarget:self action:@selector(undoPressFinish:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem* navButton = [[[UIBarButtonItem alloc] initWithCustomView:undoButton] autorelease];
self.navigationItem.rightBarButtonItem = navButton;

您不一定要将UIBarButtonItem添加为rightBarButtonItem,这是向您展示如何使用自定义视图创建UIBarButtonItem的简单方法,该自定义视图是您要处理事件的UIButton。

您需要通过维护状态来实现undoPressStart:和undoPressFinish:我会说,在开始时,存储当前的NSDate或时间的一些细粒度表示。完成后,如果检查已经过的时间以及是否超过某个阈值,则显示菜单 - 否则(以及从未捕获开始日期)执行撤消。

作为改进,您可能还想观察UIControlEventTouchDragExit事件以取消长按。