防止或检测从iOS 8键盘传递的事件

时间:2014-10-30 11:07:44

标签: ios ios8 keyboard-events

在我们的iOS 8应用程序中,搜索界面与App Store应用程序的搜索界面类似,不再可靠。当用户点击一个键时,键盘有时会关闭,甚至执行一个动作。

部分原因是tap事件被传递到较低层,即关闭键盘(烟雾屏幕),导航到搜索结果(带搜索结果的UITableView)或执行搜索(带搜索词建议的UITableView) )。

由于某些未知原因,只要用户留在应用中,它就能正常工作。但是,如果他/她转到另一个应用程序然后返回,则会传递事件。此行为会影响所有iOS 8版本(8.0.x,8.1)。

我们如何阻止键盘传递点击事件或我们如何检测此类事件(例如来自tableView:didSelectRowAtIndexPath:)?

问题" Keyboard intermittently disappears when editing using IOS 8"虽然我无法弄清楚如何将这种丑陋的黑客应用到我的情况中,但似乎也提到了同样的问题。


我在Apple的开发者论坛中发现了类似的post。不幸的是,它没有答案,并且在同一时间存档:

  

我在视图层次结构的视图上覆盖了-hitTest:withEvent:   我检查它是否被触摸并将触摸转移到它   子视图并触发选择器以关闭键盘。

     

在iOS 7上(更奇怪的是,当应用程序在iOS 8上启动时)   完美的工作和-hitTest:withEvent:永远不会被调用   视图位于键盘后面,用户点击键盘。

     

但是在iOS 8上,如果用户将应用程序发送到后台并带来   它回到前台,点击键盘上的任何东西都会   trigger -hitTest:withEvent:好像视图位于键盘上方   视图层次结构。我已经使用Reveal.app来验证它不是   在键盘上方,它落后于预期。

     

任何人都对可能发生的事情有任何想法?我创建了一个样本   项目并将其附加到Apple的雷达上,因为这看起来像一个bug   在iOS 8上,不能以相同的方式持续工作。

更新

我的搜索屏幕包含两个视图(彼此重叠):没有搜索结果时可见的背景视图,如果搜索结果可用,则可以看到表格视图。除此之外,如果搜索栏变为活动状态,我会动态添加两个额外的视图:可以点击以结束搜索文本条目的烟雾类视图和显示搜索文本建议的表视图。所有四个视图都直接包含在视图控制器的主视图中,并覆盖整个区域。

现在有趣的是,键盘转发事件是两个动态添加的视图,而不是两个始终存在的低视图。

3 个答案:

答案 0 :(得分:2)

我认为将点击事件传递给键盘下方的视图会产生错误。正如我在同一时间发现只有动态添加的视图受到影响而不是那些属于Interface Builder文件的视图一样,我现在想出一个解决方法:如果键盘出现,我缩小了这两个视图,因此它们不会延伸到键盘下方。当键盘消失时,我再次长大它们。

所以这就是代码。最上面(和不包括)[[NSNotificationCenter defaultCenter]的上半部分之前已存在。其余的是解决方法。

- (BOOL) searchBarShouldBeginEditing: (UISearchBar*) searchBar {

    // calculate from for entire area
    CGRect frame = ...  // omitted

    // add smoke screen
    _smokeScreen = [UIButton buttonWithType: UIButtonTypeCustom];
    _smokeScreen.frame = frame;
    _smokeScreen.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    _smokeScreen.backgroundColor = [UIColor colorWithWhite: 0.0f alpha: 0.5f];
    [_smokeScreen addTarget: self action: @selector(smokeScreenPressed:) forControlEvents: UIControlEventTouchDown];
    [self.view addSubview: _smokeScreen];

    // add table view for search term suggestions
    _suggestionTableView = [[SearchControllerTableView alloc] initWithFrame:frame style:UITableViewStylePlain];
    _suggestionTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    _suggestionTableView.dataSource = self;
    _suggestionTableView.delegate = self;
    _suggestionTableView.searchController = self;
    _suggestionTableView.hidden = YES;
    [self.view addSubview:_suggestionTableView];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:)
                                                 name:UIKeyboardDidShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification object:nil];

    return YES;
}


- (void) keyboardDidShow:(NSNotification *) notification
{
    // shrink the smoke screen area and the table view because otherwise they'll receive tap events from the keyboard
    CGRect screenRect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGRect windowRect = [self.view.window convertRect:screenRect fromWindow:nil];
    CGRect viewRect = [self.view convertRect:windowRect fromView:nil];

    [self setBottom: viewRect.origin.y];
}


- (void) keyboardWillHide:(NSNotification *) notification
{
    // grow the views again
    [self setBottom: self.view.frame.size.height];
}


- (void) setBottom: (CGFloat)y
{
    CGRect frame = _suggestionTableView.frame;
    frame.size.height = y - frame.origin.y;
    _suggestionTableView.frame = frame;

    frame = _smokeScreen.frame;
    frame.size.height = y - frame.origin.y;
    _smokeScreen.frame = frame;
}

答案 1 :(得分:0)

您可以尝试使用视图属性userInteractionEnabled或 搜索视图时调用exclusiveTouch

答案 2 :(得分:0)

我使用Xamarin.iOS遇到了这个问题,这是Xamarin.iOS使用C#的解决方案。

WillMoveToSuperview方法中,观察键盘显示/隐藏事件并将键盘框架存储在变量KeyboardEndFrame中:

 if (newsuper != null)
 {
     var wrThis = new WeakReference<XInterceptTouchView> (this);
     // add notification observe
     keyboardDidShow = UIKeyboard.Notifications.ObserveDidShow ((sender, e) =>
     {
         XInterceptTouchView interceptTouchView;
         if (wrThis.TryGetTarget (out interceptTouchView))
         {
             interceptTouchView.KeyboardEndFrame = e.FrameEnd;
         }
     });
     keyboardDidHide = UIKeyboard.Notifications.ObserveDidHide ((sender, e) =>
     {
         XInterceptTouchView interceptTouchView;
         if (wrThis.TryGetTarget (out interceptTouchView))
         {
             interceptTouchView.KeyboardEndFrame = e.FrameEnd;
         }
     });
 }
 else
 {
     // remove notification observe
     keyboardDidShow?.Dispose ();
     keyboardDidHide?.Dispose ();
 }

HitTest方法中,使用窗口获取键盘窗口和处理触摸事件:

if (KeyboardEndFrame.Contains (point))
{
    IntPtr handle = ObjCRuntime.Class.GetHandle ("UITextEffectsWindow");
    if (handle != IntPtr.Zero)
    {
        var keyboardWindow = UIApplication.SharedApplication.Windows.FirstOrDefault (w => w.IsKindOfClass (new ObjCRuntime.Class ("UITextEffectsWindow")));
        if (keyboardWindow != null)
            return keyboardWindow.HitTest (point, uievent);
    }
}

var hitTestView = base.HitTest (point, uievent);
this.EndEditing (true);
return hitTestView;