UISearchbar clearButton заставляет клавиатуру появляться
У меня есть UISearchBar, который действует как живой фильтр для представления таблицы. Когда клавиатура отклоняется с помощью endEditing: текст запроса и серая круглая "четкая" кнопка остаются. Отсюда, если я коснусь серой кнопки "clear", клавиатура снова появляется, когда текст очищается.
Как это предотвратить? Если клавиатура в данный момент не открыта, я хочу, чтобы эта кнопка очищала текст без повторного открытия клавиатуры.
Существует метод протокола, который вызывается при нажатии кнопки очистки. Но отправка UISearchBar сообщения resignFirstResponder не оказывает никакого влияния на клавиатуру.
Ответы
Ответ 1
Это старый вопрос, и я просто столкнулся с той же проблемой и сумел решить его следующим образом:
Когда метод searchBar:textDidChange:
UISearchBarDelegate вызван из-за того, что пользователь нажал кнопку "clear", searchBar еще не стал первым ответчиком, поэтому мы можем воспользоваться этим, чтобы обнаружить, когда пользователь на самом деле предназначен для очистки поиска, а не для привлечения внимания к поисковому бару и/или выполнения чего-то еще.
Чтобы отслеживать это, нам нужно объявить BOOL
ivar в нашем viewController, который также является делегатом searchBar (позвоните ему shouldBeginEditing
) и установите его с начальным значением YES
(предположим, что наш viewController класс называется SearchViewController):
@interface SearchViewController : UIViewController <UISearchBarDelegate> {
// all of our ivar declarations go here...
BOOL shouldBeginEditing;
....
}
...
@end
@implementation SearchViewController
...
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
...
shouldBeginEditing = YES;
}
}
...
@end
Позже, в UISearchBarDelegate, мы реализуем методы searchBar:textDidChange:
и searchBarShouldBeginEditing:
:
- (void)searchBar:(UISearchBar *)bar textDidChange:(NSString *)searchText {
NSLog(@"searchBar:textDidChange: isFirstResponder: %i", [self.searchBar isFirstResponder]);
if(![searchBar isFirstResponder]) {
// user tapped the 'clear' button
shouldBeginEditing = NO;
// do whatever I want to happen when the user clears the search...
}
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)bar {
// reset the shouldBeginEditing BOOL ivar to YES, but first take its value and use it to return it from the method call
BOOL boolToReturn = shouldBeginEditing;
shouldBeginEditing = YES;
return boolToReturn;
}
В принципе, это.
Лучшие
Ответ 2
Я обнаружил, что resignFirstResponder не работает, когда textDidChange вызывается с сенсорного экрана на кнопку "clear". Однако использование performSelection: withObject: afterDelay:
кажется эффективным способом:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if ([searchText length] == 0) {
[self performSelector:@selector(hideKeyboardWithSearchBar:) withObject:searchBar afterDelay:0];
}
}
- (void)hideKeyboardWithSearchBar:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
}
Ответ 3
Я нашел довольно безопасный способ узнать, нажата ли кнопка очистки, и игнорировать времена, когда пользователь просто удаляет последний символ UISearchBar. Вот он:
- (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
_isRemovingTextWithBackspace = ([searchBar.text stringByReplacingCharactersInRange:range withString:text].length == 0);
return YES;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if (searchText.length == 0 && !_isRemovingTextWithBackspace)
{
NSLog(@"Has clicked on clear !");
}
}
Довольно простой и понятный, не так ли? Единственное, что нужно отметить, это то, что если пользователь нажимает кнопку очистки при редактировании UISextBield UITextField, у вас будет два пинга, тогда как вы получите только один, если пользователь нажмет на него, когда он не редактируется.
Изменить:
Я не могу проверить его, но вот быстрая версия, как в Rotem:
var isRemovingTextWithBackspace = false
func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool
{
self.isRemovingTextWithBackspace = (NSString(string: searchBar.text!).stringByReplacingCharactersInRange(range, withString: text).characters.count == 0)
return true
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String)
{
if searchText.characters.count == 0 && !isRemovingTextWithBackspace
{
NSLog("Has clicked on clear !")
}
}
Обновление @Rotem (Swift2):
var isRemovingTextWithBackspace = false
func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
self.isRemovingTextWithBackspace = (NSString(string: searchBar.text!).stringByReplacingCharactersInRange(range, withString: text).characters.count == 0)
return true
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.characters.count == 0 && !isRemovingTextWithBackspace {
NSLog("Has clicked on clear!")
}
}
Ответ 4
Я использовал комбинацию ответа @boliva, а также @radiospiel ответ на другой вопрос SO:
@interface SearchViewController : UIViewController <UISearchBarDelegate> {
// all of our ivar declarations go here...
BOOL shouldBeginEditing;
....
}
...
@end
@implementation SearchViewController
...
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
...
shouldBeginEditing = YES;
}
}
...
- (void) searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText {
// TODO - dynamically update the search results here, if we choose to do that.
if (![searchBar isFirstResponder]) {
// The user clicked the [X] button while the keyboard was hidden
shouldBeginEditing = NO;
}
else if ([searchText length] == 0) {
// The user clicked the [X] button or otherwise cleared the text.
[theSearchBar performSelector: @selector(resignFirstResponder)
withObject: nil
afterDelay: 0.1];
}
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)bar {
// reset the shouldBeginEditing BOOL ivar to YES, but first take its value and use it to return it from the method call
BOOL boolToReturn = shouldBeginEditing;
shouldBeginEditing = YES;
return boolToReturn;
}
@end
Ответ 5
Лучшее решение из моего опыта - просто положить UIButton
(с четким фоном и без текста) над кнопкой очистки системы и подключить IBAction
С автозапуском его просто больше, чем просто
- (IBAction)searchCancelButtonPressed:(id)sender {
[self.searchBar resignFirstResponder];
self.searchBar.text = @"";
// some of my stuff
self.model.fastSearchText = nil;
[self.model fetchData];
[self reloadTableViewAnimated:NO];
}
Ответ 6
В вашем методе endEditing, почему бы вам не очистить UISearchBar и нет? Так как это должно быть там, где вы тоже уходите в отставку, это имеет смысл.
Ответ 7
Из вызовов делегата панели поиска предлагается принять изменение от старого значения до нового: вы можете обнаружить, что новое значение было равно нулю, а также старое значение, которое не было равно нулю, и индикатор того, что пользователь не набрал ничего, поскольку клавиатура была в последний раз - тогда в этом случае отмените первый ответчик для панели поиска. Не уверен, будет ли отображаться клавиатура на мгновение.
У меня очень похожая ситуация и я могу попробовать это.
Ответ 8
Прикосновение к кнопке очистки приводит к тому, что параметр searchText
пуст. Другой способ добиться этого - проверить пустой текст в - (void)searchBar:(UISearchBar *)bar textDidChange:(NSString *)searchText
:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if([searchText length] == 0)
{
[self dismissSearch];
}
else
{
self.searchResultsTable.hidden = YES;
[self handleSearchForString:searchText];
}
}
- (void)dismissSearch
{
[self.searchBar performSelector: @selector(resignFirstResponder)
withObject: nil
afterDelay: 0.1];
self.searchResultsTable.hidden = YES;
}
Ответ 9
Для тех из вас, кто использует UISearchController
в iOS 8 и выше, вам нужно просто подклассифицировать UISearchController
. Для полноты вам также может потребоваться скрыть кнопку отмены, так же как и я, так как очистка текста от UISearchBar
фактически отменяет поиск. Я добавил этот код ниже, если вы хотите его использовать.
Преимущество этого в том, что вы сможете использовать его для любого класса и любого представления, вместо того, чтобы требовать подкласс UIViewController
. Я даже включу, как инициализировать мой UISearchController
в нижней части этого решения.
FJSearchBar
Этот класс нужно переопределить, если вы хотите скрыть кнопку отмены, как я. Маркировка searchController.searchBar.showsCancelButton = NO
, похоже, не работает в iOS 8. Я не тестировал iOS 9.
FJSearchBar.h
Пусто, но размещена здесь для полноты.
@import UIKit;
@interface FJSearchBar : UISearchBar
@end
FJSearchBar.m
#import "FJSearchBar.h"
@implementation FJSearchBar
- (void)setShowsCancelButton:(BOOL)showsCancelButton {
// do nothing
}
- (void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated {
// do nothing
}
@end
FJSearchController
Здесь вы хотите внести реальные изменения. Я разделил UISearchBarDelegate
на свою собственную категорию, потому что, IMHO, категории делают классы более чистыми и удобными в обслуживании. Если вы хотите сохранить делегат в интерфейсе/реализации основного класса, вы более чем можете это сделать.
FJSearchController.h
@import UIKit;
@interface FJSearchController : UISearchController
@end
@interface FJSearchController (UISearchBarDelegate) <UISearchBarDelegate>
@end
FJSearchController.m
#import "FJSearchController.h"
#import "FJSearchBar.h"
@implementation FJSearchController {
@private
FJSearchBar *_searchBar;
BOOL _clearedOutside;
}
- (UISearchBar *)searchBar {
if (_searchBar == nil) {
// if you're not hiding the cancel button, simply uncomment the line below and delete the FJSearchBar alloc/init
// _searchBar = [[UISearchBar alloc] init];
_searchBar = [[FJSearchBar alloc] init];
_searchBar.delegate = self;
}
return _searchBar;
}
@end
@implementation FJSearchController (UISearchBarDelegate)
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
// if we cleared from outside then we should not allow any new editing
BOOL shouldAllowEditing = !_clearedOutside;
_clearedOutside = NO;
return shouldAllowEditing;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
// hide the keyboard since the user will no longer add any more input
[searchBar resignFirstResponder];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (![searchBar isFirstResponder]) {
// the user cleared the search while not in typing mode, so we should deactivate searching
self.active = NO;
_clearedOutside = YES;
return;
}
// update the search results
[self.searchResultsUpdater updateSearchResultsForSearchController:self];
}
@end
Некоторые примечания:
- Я положил строку поиска и
BOOL
как частные переменные вместо свойств, потому что
- Они более легкие, чем частные.
- Им не нужно видеть или изменять внешний мир.
- Мы проверяем, является ли
searchBar
первым ответчиком. Если это не так, мы фактически деактивируем контроллер поиска, потому что текст пуст, и мы больше не ищем. Если вы уверены, что действительно, вы также можете убедиться, что searchText.length == 0
.
-
searchBar:textDidChange:
вызывается перед searchBarShouldBeginEditing:
, поэтому мы обработали его в этом порядке.
- Я обновляю результаты поиска каждый раз, когда текст изменяется, но вы можете переместить
[self.searchResultsUpdater updateSearchResultsForSearchController:self];
в searchBarSearchButtonClicked:
, если вы хотите, чтобы поиск выполнялся после нажатия пользователем кнопки поиска.
Ответ 10
Быстрая версия ответа @boliva.
class MySearchContentController: UISearchBarDelegate {
private var searchBarShouldBeginEditing = true
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchBarShouldBeginEditing = searchBar.isFirstResponder
}
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
defer {
searchBarShouldBeginEditing = true
}
return searchBarShouldBeginEditing
}
}
Ответ 11
Я столкнулся с этим несколько раз. Я очень ценю ответы, которые дали люди.
В конечном счете, мне бы очень хотелось, чтобы Apple просто позволила нам (разработчикам) обнаружить, когда нажата кнопка очистки.
Очевидно, что нажатие на него обнаруживается, потому что любой текст в окне поиска очищается.
Я догадываюсь, что сейчас это не очень высоко в их списке приоритетов... Но я действительно хочу, чтобы кто-то из Apple дал UISearchBar немного любви!