2009-08-17 41 views

回答

2

我从iphonedevbook(样本代码项目04)得到的另一个想法是使用一个大的透明按钮,它位于所有其他控件后面,除了点击所有其他控件之外什么也不做,只是退出所有第一响应者。即如果用户点击没有更重要的控件的地方 - 这是直观的行为 - 搜索栏和键盘消失。

+0

这与我上面的建议实际上是一样的。实施起来可能会更简单一些。 – Amagrammer 2009-08-18 13:40:09

+0

谢谢豪克!创建透明按钮并处理touchup事件以辞退第一个响应者的技巧。 – 2009-08-18 15:21:47

+0

我现在有一个其他问题是让我们说我有一个包含该透明按钮后面的mkmapview的视图。一旦searchBar消失,我怎样才能重新激活地图? – 2009-08-18 15:28:05

0

首先,您需要对搜索栏的引用。假设您的控制器对象具有对象引用UISearchBar * theSearchBar,并且您在创建UISearchBar对象时分配它。

接下来,您需要检测是否触摸了包含视图。被触摸的视图“知道”,但您需要将该信息提供给控制器。可悲的是,苹果公司并没有提供一个简单的方法来做到这一点,但也不是那么难。

我的解决方案是用一个UIControl替换UIViewController对象通常创建的标准UIView,然后使UIViewController响应触摸事件。

MainController.m

- (void) loadView { 
    UIControl *control = [[UIControl alloc] initWithFrame: <desired frame>]; 
[control addTarget: self action: @selector(touchUpInside) 
      forControlEvents: UIControlEventTouchUpInside]; 
     // or touch down events, or whatever you like 
    self.view = control; 
    [control release]; 
} 

- (void) viewDidLoad { 
    [super viewDidLoad]; 
    theSearchBar = [[UISearchBar alloc] initWithFrame: <desired frame>]; 

    // insert code to finish customizing the search bar 

    [self.view addSubview: theSearchBar]; 
} 

- (void) touchUpInside { 
    if [theSearchBar isFirstResponder] { 
     // grab any data you need from the search bar 
     [theSearchBar resignFirstResponder]; 
    } 
} 

MainController.h

@interface MainController : UIViewController 
{ 
    UISearchBar *theSearchBar; 
} 

澄清:

只有一个单一的对象 - 我们称之为类MainController - 这是UIViewController的子类。上面列出的所有方法都在MainController中实现。 theSearchBar在.h文件中声明为UISearchBar *。

您是使用Interface Builder定义视图和控制器吗?如果是这样,我建议你学会如何不使用它 - 一旦你进入我们在这里讨论的那种技巧,它变得更加困难而不是帮助 - 我根本不使用它。

+0

如何从touchUpInside事件获取对searchBar的引用?我在包含搜索栏的viewcontroller类中有touchUpInside。 – 2009-08-17 16:53:00

+0

你的意思是,为了调用resignFirstResponder?如果您在创建时将其作为参考保存,您已经拥有它。 – Amagrammer 2009-08-17 17:54:59

+0

我有点困惑。上面的代码应该与我创建搜索栏的代码位于不同的视图控制器中吗?另外为什么你在你的loadView例程中创建一个UIControl而不是UISearchBar? – 2009-08-17 18:08:41

3

我做到了这一点通过使用UITapGestureRecognizer:

UIGestureRecognizer* cancelGesture; 

- (void) backgroundTouched:(id)sender { 
    [self.view endEditing:YES]; 
} 

#pragma mark - UISearchBarDelegate 

-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar { 
    cancelGesture = [UITapGestureRecognizer new]; 
    [cancelGesture addTarget:self action:@selector(backgroundTouched:)]; 
    [self.view addGestureRecognizer:cancelGesture]; 
} 

-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar { 
    if (cancelGesture) { 
     [self.view removeGestureRecognizer:cancelGesture]; 
     [cancelGesture release]; 
     cancelGesture = nil; 
    } 
} 

的代码是一个光秃秃的,但你可以看到的意图。当SearchBar开始编辑时,您将一个轻击手势识别器附加到视图控制器的视图中,并在停止编辑时将其删除。

你可以解决一些问题:如果你点击除键盘或搜索栏的文本字段以外的任何东西,识别器将捕获点击 - 所以如果你使用清除,取消,范围或结果按钮,他们将不会正确响应。

在我的特殊场景中,我有一个覆盖视图的暴露区域的UITableView,因此我附加了手势识别器而不是视图控制器主视图,从而隔离手势将响应的区域。

2

我最终使用了Hauke's和Beau Scott的方法。我遇到了两个使用他们的解决方案的问题:

1)如果屏幕上还有其他东西,点击它不会导致resignFirstResponder被调用。例如,如果用户点击按钮而不是按钮周围的空间,则该按钮将吃掉该事件。然而,Beau Scott的解决方案解决了这个问题。

2)点击搜索栏本身会导致resignFirstResponder被调用。显然,当你点击UISearchBar时,你不希望键盘消失。下面描述的一个小改变解决了这个问题

我最终建立了我的观点如下。父视图有两个子项--UISearchBar和一个子视图,它包含我的其他UI元素。子视图占用UISearchBar下面的整个屏幕。然后我用博·斯科特的确切的代码添加和删除手势识别,而不是增加它self.view我把它添加到子视图:

IBOutlet UIView *gestureRecognizer; 

...

-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar { 
    cancelGesture = [UITapGestureRecognizer new]; 
    [cancelGesture addTarget:self action:@selector(backgroundTouch:)]; 
    [gestureRecognizer addGestureRecognizer:cancelGesture]; 
} 

-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar { 
    if (cancelGesture) { 
     [gestureRecognizer removeGestureRecognizer:cancelGesture]; 
     [cancelGesture release]; 
     cancelGesture = nil; 
    } 
} 
12

添加在父视图中双击手势(在的UISearchBar的)

[self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:searchBar action:@selector(resignFirstResponder)]]; 
+1

如果'self''是一个'''UIView''',这段代码是有意义的。但大多数情况下'''self'''实际上是一个'''UIViewController''',所以这应该是'''[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self.searchBar action: @selector(resignFirstResponder)]];''' – mikeho 2016-03-06 05:34:27

0

@Gia党的答案是简单的,但我不子类UIView,只有UIViewController,所以我的CAL l是略有不同。另外,由于我不知道实际拨打resignFirstResponder的开销,我宁愿先检查。这是更多的代码,但由于所有这些都是在主线程上完成的(这可能会减慢UI),所以我宁愿先检查一下。

@implementation MyController : UIViewController { 
@private 
    UISearchController *_uiSearchController; 
} 

- (void)viewDidLoad { 
    // add tap on view to resign the responder if we're in the middle of typing in the search 
    UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeKeyboardIfNeeded)]; 
    [self.view addGestureRecognizer:tapGestureRecognizer]; 
} 

- (void)closeKeyboardIfNeeded { 
    if (![_uiSearchController.searchBar isFirstResponder]) { 
     return; 
    } 
    [_uiSearchController.searchBar resignFirstResponder]; 
} 

@end 

至于其他答案,要小心不断重新创建对象。无论是创建本身还是通过ARC垃圾收集,性能总会受到影响,并且这些事情会降低主线程速度。根据您在主线程中所做的操作,它可能会对性能产生重大影响。

相关问题