ios 无法将 searchBar 设置为 firstResponder
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27951965/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cannot set searchBar as firstResponder
提问by user3411663
I have a searchBar I'm setting in a tableviewcontroller. i've referenced this similar question UISearchBar cannot become first responder after UITableView did re-appearbut am still unable to set it as first responder. In .h file:
我在 tableviewcontroller 中设置了一个 searchBar。我已经引用了这个类似的问题UISearchBar 在 UITableView 重新出现后无法成为第一响应者,但我仍然无法将其设置为第一响应者。在 .h 文件中:
@property (strong, nonatomic) UISearchController *searchController;
@property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
In view didload:
在视图didload中:
self.searchController = [[UISearchController alloc]initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0);
self.tableView.tableHeaderView = self.searchController.searchBar;
And in viewDidAppear:
在 viewDidAppear 中:
-(void)viewDidAppear:(BOOL)animated {
[self.searchController setActive:YES];
[self.searchController.searchBar becomeFirstResponder];
[super viewDidAppear:animated];
}
When I segue to the view the searchBar animates, but no keyboard appears.
当我转到视图时,searchBar 会进行动画处理,但没有出现键盘。
回答by edwardmp
I noticed this issue too. What seems to happen is the call to becomeFirstResponder
is done when the searchController is still 'loading'. If you comment out becomeFirstResponder
you notice that there is no difference. So we need a way to call becomeFirstResponder after the searchController is 'done' loading.
我也注意到了这个问题。似乎发生的是becomeFirstResponder
当 searchController 仍在“加载”时调用。如果您注释掉,becomeFirstResponder
您会注意到没有区别。所以我们需要一种在 searchController 加载完成后调用 becomeFirstResponder 的方法。
When I looked at various delegate methods I noticed there is a delegate method:
当我查看各种委托方法时,我注意到有一个委托方法:
- (void)didPresentSearchController:(UISearchController *)searchController
This method is called right after the searchController has been presented. Then I make the call to becomeFirstResponder
:
这个方法在 searchController 出现后立即调用。然后我打电话给becomeFirstResponder
:
- (void)didPresentSearchController:(UISearchController *)searchController
{
[searchController.searchBar becomeFirstResponder];
}
This fixes the problem. You will notice that when the searchController is loaded, the searchbar now has focus.
这解决了问题。您会注意到,当 searchController 加载时,搜索栏现在具有焦点。
回答by mislovr
The solution with
- (void)didPresentSearchController:(UISearchController *)searchController
did not work, since this delegate method is called only when the user taps on the search bar...
带有 - 的解决方案(void)didPresentSearchController:(UISearchController *)searchController
不起作用,因为仅当用户点击搜索栏时才会调用此委托方法...
However, this solution did work:
但是,此解决方案确实有效:
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self performSelector:@selector(showKeyboard) withObject:nil afterDelay:0.1];
}
- (void) showKeyboard
{
[self.searchController.searchBar becomeFirstResponder];
}
Swift 3
斯威夫特 3
delay(0.1) { self.searchController.searchBar.becomeFirstResponder() }
func delay(_ delay: Double, closure: @escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
回答by Roland T.
Well, I found the solution that is actually perfectly working for me.
好吧,我找到了实际上对我来说非常有效的解决方案。
Don't call [self.searchController setActive:YES];
before calling [self.searchController.searchBar becomeFirstResponder];
打电话[self.searchController setActive:YES];
之前不要打电话[self.searchController.searchBar becomeFirstResponder];
What's better, don't call [self.searchController setActive:YES];
at all.
最好不要打电话[self.searchController setActive:YES];
。
Call only [self.searchController.searchBar becomeFirstResponder];
and the keyboard just pops out as it should, without any delay.
只调用[self.searchController.searchBar becomeFirstResponder];
,键盘就会按原样弹出,没有任何延迟。
It seems to be somewhat like a bug and a lot of people are confirming it. For example, check here: When assigning focus via becomeFirstResponder to UISearchController's UISearchBar, the keyboard does not appear
这似乎有点像一个错误,很多人都在确认它。例如,在这里检查:通过becomeFirstResponder 将焦点分配给UISearchController 的UISearchBar 时,键盘不会出现
回答by W?odzimierz Wo?niak
Swift 4, iOS 11
斯威夫特 4,iOS 11
It works for me
这个对我有用
// 1.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
resultSearchController.isActive = true
}
// 2. ->> UISearchControllerDelegate
func didPresentSearchController(_ searchController: UISearchController) {
DispatchQueue.main.async {
searchController.searchBar.becomeFirstResponder()
}
}
回答by Tan Vu
The function searchController.searchBar.becomeFirstResponder()
must be called in the main thread and after searchController.active = true
in the viewDidLoad method. Here're the full solution. It works on iOS 9.3
该函数searchController.searchBar.becomeFirstResponder()
必须在主线程中调用,然后searchController.active = true
在 viewDidLoad 方法中调用。这是完整的解决方案。它适用于 iOS 9.3
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
searchController.active = true
Async.main {
self.searchController.searchBar.becomeFirstResponder()
}
}
回答by Mason Black
Very similar to other answers, but I had to access the main queuein the ViewDidAppear
.
The SearchBarController
can't be acted upon until the View
appears and then can only be done so in the main queue for UI
:
非常相似,其他的答案,但我不得不进入主队列中ViewDidAppear
。将SearchBarController
不能被作用,直到View
出现,然后只能在主队列这样做UI
:
searchController.active = true // doubtful whether this is needed
dispatch_async(dispatch_get_main_queue(), {
self.searchController.searchBar.becomeFirstResponder()
});
回答by Vitya Shurapov
Easy Swift3variant:
简单的Swift3变体:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.titleView = mySearchController.searchBar
mySearchController.searchResultsUpdater = self
mySearchController.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
DispatchQueue.main.async {
self.mySearchController.isActive = true
}
}
func presentSearchController(_ searchController: UISearchController) {
mySearchController.searchBar.becomeFirstResponder()
}
It works ;-)
有用 ;-)
回答by UnRewa
Swift 5
solution:
Swift 5
解决方案:
override func viewDidLoad() {
super.viewDidLoad()
definesPresentationContext = true
searchController.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
searchController.isActive = true
}
extension ViewController: UISearchControllerDelegate {
func didPresentSearchController(_ searchController: UISearchController) {
DispatchQueue.main.async {[weak self] in
self?.searchController.searchBar.becomeFirstResponder()
}
}
}
回答by Tommie C.
Alternative Approach
替代方法
This answer looks at a number of issues related to this occurrence and explains the debugging logic used to isolate and determine the specific cause of the problem in my case. Along the way, I share other possibilities that might have worked in other situations and explain why this works in my situation.
此答案着眼于与此事件相关的许多问题,并解释了在我的案例中用于隔离和确定问题的具体原因的调试逻辑。一路上,我分享了在其他情况下可能有效的其他可能性,并解释了为什么这在我的情况下有效。
tldr; Look at the self.definesPresentationContext = true, the isBeingDismissed, isBeingPresented, canBecomeFirstResponder, and delegate assignment of the SearchController, the Searchbar, SearchResultsUpdater and their delegate methods.
tldr; 查看 self.definesPresentationContext = true、isBeingDismissed、isBeingPresented、canBecomeFirstResponder 和 SearchController、Searchbar、SearchResultsUpdater 及其委托方法的委托分配。
(Sourceof self.definesPresentationContext
solution - See SO answer)
(资料来源的self.definesPresentationContext
解决方案-看到这么回答)
One thing to keep in mind is the context of how the SearchBar is being presented. Embedded in a toolbar, navigation bar, another UIView, as an input or input accessory view. All of which, I've found to have some impact on the timing and internal animation of the search bar as it is being presented or dismissed.
要记住的一件事是 SearchBar 呈现方式的上下文。嵌入在工具栏、导航栏、另一个 UIView 中,作为输入或输入附件视图。我发现所有这些都会对搜索栏显示或关闭时的时间和内部动画产生一些影响。
I've attempted all of the solutions presented and none of these worked until I reconsidered how I was trying to use the searchBar. In my case, I was pushing a controller (B)with a search controller from a controller (A)that already had an initial searchcontroller on it. I programmatically embedded each of the search controllers within the titleView of my navigation item when doing a pull refresh.
我已经尝试了所有提出的解决方案,但在我重新考虑如何尝试使用 searchBar 之前,这些解决方案都没有奏效。就我而言,我正在推送一个控制器(B)和一个来自控制器(A)的搜索控制器,该控制器(A)上已经有一个初始搜索控制器。在进行拉刷新时,我以编程方式将每个搜索控制器嵌入到导航项的 titleView 中。
The answers suggesting adding searchbar.becomeFirstResponder()
into the life cycle didn't make sense for my use-case since the view was fully loaded by the time I wanted to insert and display my search bar into the navigationItem. The logic also seemed confusing since the view controller lifecycle methods should already be operating on the main thread. Adding a delay to the presentation also seemed to be an interference with the internal operations of the display and animation used by the system.
建议添加searchbar.becomeFirstResponder()
到生命周期中的答案对我的用例没有意义,因为在我想要将我的搜索栏插入并显示到导航项时视图已完全加载。逻辑似乎也很混乱,因为视图控制器生命周期方法应该已经在主线程上运行了。在演示中添加延迟似乎也干扰了系统使用的显示和动画的内部操作。
I found that calling my function to toggle the insertion worked when I pushed the view controller from controllerA but the keyboard would not display properly when pushed from controllerB. The difference between these two situations was that controllerA was a static tableview controller and controllerB had a tableview controller that I had made searchable by adding its own search controller.
我发现当我从控制器 A 推送视图控制器时调用我的函数来切换插入工作,但从控制器 B 推送时键盘无法正确显示。这两种情况的区别在于 controllerA 是一个静态 tableview 控制器,controllerB 有一个 tableview 控制器,我通过添加自己的搜索控制器使其可搜索。
e.g. controllerAwith searchbar segues to controllerBwith searchbar
例如controllerA与搜索栏塞格斯到controllerB与搜索栏
Using a number of breakpoints and examining the status of the searchController and the searchbar at different points I was able to determine that the searchController.canBecomeFirstResponder
was returning false
. I also found that I needed to set the SearchResultsUpdater
to self
and the delegates on both the searchController and the searchBar.
使用多个断点并检查 searchController 和搜索栏在不同点的状态,我能够确定searchController.canBecomeFirstResponder
正在返回false
. 我还发现我需要在 searchController 和 searchBar 上设置SearchResultsUpdater
toself
和委托。
I finally noted that setting self.definesPresentationContext = true
on controllerA was not allowing the keyboard to be displayed when I pushed controllerB onto the navigation stack. My solution was to move the self.definesPresentationContext = true
to viewDidAppear
on controllerA and in the prepare(for:sender:)
method of controllerA I change it to self.definesPresentationContext = false
when the destination is controllerB. This resolved the keyboard display issue in my case.
我终于注意到,self.definesPresentationContext = true
当我将控制器 B 推入导航堆栈时,控制器 A 上的设置不允许显示键盘。我的解决方案是移动self.definesPresentationContext = true
到viewDidAppear
上controllerA并在prepare(for:sender:)
controllerA我将其更改为方法self.definesPresentationContext = false
时,目的地是controllerB。这解决了我的键盘显示问题。
A word on animation~ I've found that when assigning things to the navigationItem or navigationBar, the system has some built in timing and default animations. I avoid adding custom animation, code in moveToParent methods, or delayed presentations because unexpected behavior occurs in many cases.
关于动画的一句话~我发现在将东西分配给导航项或导航栏时,系统有一些内置的计时和默认动画。我避免添加自定义动画、moveToParent 方法中的代码或延迟演示,因为在许多情况下会发生意外行为。
Why this solution works
为什么这个解决方案有效
Apple documentationon definesPresentationContext
indicates the default behavior and notes some situations where this context adjusts the behavior the controller assigned to manage the keyboard appearance. In my case controllerA was assgined to manage the presentation rather than controllerB, so I just changed that behavior by adjusting this value:
苹果文档上definesPresentationContext
显示的默认行为,并指出其中此背景下调整行为分配管理键盘外观控制器的一些情况。在我的例子中,控制器 A 被分配来管理演示而不是控制器 B,所以我只是通过调整这个值来改变这种行为:
When using the currentContext or overCurrentContext style to present a view controller, this property controls which existing view controller in your view controller hierarchy is actually covered by the new content. When a context-based presentation occurs, UIKit starts at the presenting view controller and walks up the view controller hierarchy. If it finds a view controller whose value for this property is true, it asks that view controller to present the new view controller. If no view controller defines the presentation context, UIKit asks the window's root view controller to handle the presentation. The default value for this property is false. Some system-provided view controllers, such as UINavigationController, change the default value to true.
当使用 currentContext 或 overCurrentContext 样式来呈现视图控制器时,此属性控制视图控制器层次结构中的哪个现有视图控制器实际上被新内容覆盖。当基于上下文的呈现发生时,UIKit 从呈现的视图控制器开始并沿着视图控制器层次结构向上走。如果它找到一个视图控制器的这个属性的值为真,它会要求该视图控制器呈现新的视图控制器。如果没有视图控制器定义表示上下文,UIKit 会要求窗口的根视图控制器来处理表示。此属性的默认值为 false。一些系统提供的视图控制器,例如 UINavigationController,将默认值更改为 true。
回答by bigDeeOT
The answer is to call becomeFirstResponder in viewDidAppear.
答案是在 viewDidAppear 中调用 becomeFirstResponder。
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
searchBar?.becomeFirstResponder()
}