当前位置:  开发笔记 > IOS > 正文

如何在UIBarButtonItem中添加UIGestureRecognizer,就像在iPad应用程序中常见的undo/redo UIPopoverController方案一样?

如何解决《如何在UIBarButtonItem中添加UIGestureRecognizer,就像在iPad应用程序中常见的undo/redoUIPopoverController方案一样?》经验,为你挑选了5个好方法。

问题

在我的iPad应用程序中,在按下并保持事件后才能将弹出窗口附加到按钮栏项目.但这似乎是撤消/重做的标准.其他应用程序如何做到这一点?

背景

我的UIKit(iPad)应用程序的工具栏中有一个撤消按钮(UIBarButtonSystemItemUndo).当我按下撤销按钮时,它会触发它的动作,即undo:,并且正确执行.

然而,在iPad上撤消/重做的"标准UE惯例"是按下撤销执行撤消,但按住按钮会显示一个弹出控制器,用户选择"撤消"或"重做"直到控制器被解除.

附加弹出控制器的常规方法是使用presentPopoverFromBarButtonItem:,我可以很容易地配置它.要仅在按住之后显示此内容,我们必须设置视图以响应"长按"手势事件,如此代码段中所示:

UILongPressGestureRecognizer *longPressOnUndoGesture = [[UILongPressGestureRecognizer alloc] 
       initWithTarget:self 
               action:@selector(handleLongPressOnUndoGesture:)];
//Broken because there is no customView in a UIBarButtonSystemItemUndo item
[self.undoButtonItem.customView addGestureRecognizer:longPressOnUndoGesture];
[longPressOnUndoGesture release];

有了这个,在按下并保持视图后,方法handleLongPressOnUndoGesture:将被调用,在这个方法中,我将配置并显示undo/redo的popover.到现在为止还挺好.

这个问题是没有附加视图.self.undoButtonItem是一个UIButtonBarItem,而不是一个视图.

可能的解决方案

1)[理想] 将手势识别器附加到按钮栏项目.可以将手势识别器附加到视图,但UIButtonBarItem不是视图.它确实具有.customView的属性,但当buttonbaritem是标准系统类型时(在这种情况下它是),该属性为nil.

2)使用另一个视图.我可以使用UIToolbar,但这需要一些奇怪的命中测试,并且如果可能的话首先是一个全面的黑客攻击.我无法想到使用其他替代视图.

3)使用customView属性.像UIBarButtonSystemItemUndo这样的标准类型没有customView(它是nil).设置customView将删除它需要的标准内容.这将相当于重新实现UIBarButtonSystemItemUndo的所有外观和功能,如果可能的话.

如何将手势识别器附加到此"按钮"?更具体地说,如何在iPad应用程序中实现标准的按住 - 显示 - 重做 - 弹出窗口?

想法?非常感谢,特别是如果有人真的在他们的应用程序中工作(我在想你,omni)并想分享......



1> Tustin2121..:

注意:这不再适用于iOS 11

尝试在工具栏的子视图列表中找到UIBarButtonItem的视图代替那个混乱,一旦将项添加到工具栏,您也可以尝试这样做:

[barButtonItem valueForKey:@"view"];

这使用键值编码框架来访问UIBarButtonItem的private _view变量,它保留了它创建的视图.

当然,我不知道Apple的私有API事件在哪里(这是用于访问公共类的私有变量的公共方法 - 不像访问私有框架来制作纯粹的Apple效果或任何东西),但是它确实有效,而且非常轻松.


这更简单,而且可能更具有前瞻性.使用私有API(除了拒绝)的一大风险是您的代码将来可能会中断.将此代码包装在`if([[sortmodeBarButtonItem valueForKey:@"view"] respondsToSelector:@selector(addGestureRecognizer :)])中会使其更加健壮.
这是访问视图的最简单,最可靠的方法.最后,这里建议的所有其他方法基本上都访问相同的变量,因此它们不再比这个更"合法" - 只是更难以检测.有没有人试图提交使用这种"valueForKey"方法的应用程序?
这非常有效.只需要在viewDidAppear中使用它,因为如果之前调用它会返回nil.有没有人使用过这种技术并成功推出了他们的应用

2> 小智..:

这是一个老问题,但它仍然出现在谷歌搜索中,所有其他答案都过于复杂.

我有一个按钮栏,带有按钮栏项,按下时调用一个动作:forEvent:方法.

在该方法中,添加以下行:

bool longpress=NO;
UITouch *touch=[[[event allTouches] allObjects] objectAtIndex:0];
if(touch.tapCount==0) longpress=YES;

如果是单击,则tapCount为1.如果是双击,则tapCount为2.如果是长按,则tapCount为零.


很棒.请注意,虽然我认为这与UILongPressGestureRecognizer略有不同,因为它在长按FYI之后首次触摸起来.
乌托邦值得10颗星。在经过5年以上的iPhone开发后,我再次遇到了这个问题,但我尝试了valueForKey **和UILongPressGestureRecognizer **方法,该方法显然不再适用于iOS 8,但** action:forEvent **方法仍然有效。大!谢谢!澄清一下:您需要将操作方法​​更改为**-(IBAction)button_hit:(id)sender forEvent:(UIEvent *)event {...} **并使用** ... @ selector( button_hit:forEvent:)**以添加目标事件或以常规方式从XCode连接。

3> v01d..:

选项1确实是可能的.不幸的是,找到UIBarButtonItem创建的UIView是一件痛苦的事情.这是我发现它的方式:

[[[myToolbar subviews] objectAtIndex:[[myToolbar items] indexOfObject:myBarButton]] addGestureRecognizer:myGesture];

这比它应该更难,但这显然是为了阻止人们使用按钮的外观和感觉来愚弄.

请注意,固定/灵活空间计为视图!

为了处理空间,你必须有一些方法来检测它们,遗憾的是SDK根本没有简单的方法来做到这一点.有解决方案,这里有一些:

1)在工具栏上从左到右将UIBarButtonItem的标记值设置为它的索引.这需要过多的手动工作才能使IMO保持同步.

2)将任何空格的启用属性设置为NO.然后使用此代码段为您设置标记值:

NSUInteger index = 0;
for (UIBarButtonItem *anItem in [myToolbar items]) {
    if (anItem.enabled) {
        // For enabled items set a tag.
        anItem.tag = index;
        index ++;
    }
}

// Tag is now equal to subview index.
[[[myToolbar subviews] objectAtIndex:myButton.tag] addGestureRecognizer:myGesture];

当然,如果您因某些其他原因禁用按钮,这可能存在陷阱.

3)手动编码工具栏并自己处理索引.由于您将自己构建UIBarButtonItem,因此您事先会知道它们在子视图中的索引.如有必要,您可以将此想法扩展到提前收集UIView以供以后使用.



4> Ben Stiglitz..:

您可以自己创建按钮,然后使用自定义视图添加按钮栏项,而不是在子视图中进行搜索.然后将GR连接到您的自定义按钮.



5> 小智..:

虽然这个问题已经超过一年了,但这仍然是一个非常烦人的问题.我已经向Apple提交了一份错误报告(rdar:// 9982911),我建议其他任何感觉相同的人都会复制它.

推荐阅读
喜生-Da
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有