2013-03-06 2 views
16

Я добавил UISearchBar в UICollectionView, а в делегате searchBar:textDidChange: отфильтруйте мою модель и позвоните по телефону [collectionView reloadData]. reloadData (а также reloadSection и т. Д.) Хочет убрать firstResponder из текстового поля панели поиска, тем самым отклоняя клавиатуру.Как фильтровать UICollectionView и держать клавиатуру вверх?

Я пытаюсь создать фильтр «живого обновления», и поэтому это раздражает, когда клавиатура исчезает после ввода каждого символа.

Любые идеи?

+0

Спасибо, что задали этот вопрос. – GeneCode

ответ

0

Я думаю, что вы вызываете метод -resignFirstResponder в SearchBar делегата, которые вызывают каждый раз, когда вы вводите значение, которое он получает отклонил

Вы находитесь в правильном пути о методах DataSource и перезагружать data.Use массив для хранения все значения представляют собой другой массив для загрузки коллекции и каждой буквы, введенной в фильтр поиска, и загружают массив данных, а затем перезагружают.

Ну, я думаю, что лучше держать клавиатуру. Это правильный стиль пользовательского интерфейса после того, как вы сделав ввод текста для поиска, вы можете отменить его вручную. Я думаю, что это лучший вариант для фильтра обновления в реальном времени.

Если вы используете кнопку для поиска, то вы можете включить опцию клавиатуры скрыть there.but живого обновления не может быть реализован при использовании такого варианта

0

Я только что создал небольшое тестовое приложение. Следующий код не скрывает клавиатуру при вводе символов в панель поиска. Тем не менее, [UITableView reloadData] не уходит в отставку.

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 
    return arc4random() % 10; 
} 

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {  
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; 
    return cell; 
} 

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { 
    [self.collectionView reloadData]; 
} 

Вы уверены, что не можете оставить его где-нибудь?

3

Если вы добавили UISearchBar в качестве заголовка к UICollectionView на reloadData вызов будет «обновить» заголовок путем удаления и повторного добавления UISearchBar заставляя его терять firstResponder.

Вы можете добавить свой UISearchBar другим способом, не используя заголовок, или переопределить reloadData, проверить, если строка поиска в настоящее время firstResponder, и если да, после вызова super, сделайте следующее:

// If we've lost first-responder, restore it. 
if ((wasFirstResponder) && (![self.searchBar isFirstResponder])) { 
    [self.searchBar becomeFirstResponder]; 
} 
+0

Хорошее объяснение. Но мне интересно, почему TableView не страдает этой проблемой. – GeneCode

0

Вот как я управлял им. У меня был UISearchBar как дополнительный заголовок в моем представлении коллекции.В текстовом didchange для SearchBar делегата я установить флаг, что поиск активен (или нет) и перезарядил CollectionView

- (void)searchBar:(UISearchBar *)_searchBar textDidChange:(NSString *)searchText 
{ 
    if([searchText isEqualToString:@""]) 
    { 
     activeSearch = FALSE; 
    } 
    else 
    { 
     activeSearch = TRUE; 
    } 
    [self filterContentForSearchText:searchText scope:nil]; 
    [self.collectionView reloadData]; 
} 

Тогда в cellForItemAtIndexPath я проверяю, если клавиатура первый Ответчик и поиск активен, если не , я делаю это первый ответчику:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    ... 

    if(activeSearch && ![searchBar isFirstResponder]) 
    { 
     [searchBar becomeFirstResponder]; 
    } 
} 
0

Я просто добавил

[searchBar becomeFirstResponder]; 

после вызова

[collectionView reloadData]; 
2

решаемые его:

UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0, 0.0, 726.0f, 44.0f)]; 
    [_collectionView addSubview:searchBar]; 
    searchBar.delegate = self; 
    [(UICollectionViewFlowLayout *)_collectionView.collectionViewLayout setSectionInset:UIEdgeInsetsMake(64, 20, 20, 20)]; 


- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { 
    [_collectionView reloadData]; 
    [searchBar becomeFirstResponder]; 
} 
6

Я столкнулся с такой же проблемой в последнее время, и потребовалось некоторое время, чтобы ее исправить. Проблема заключается в том, что когда текстовое поле вложено в ReusableCollectionView, следующее не работает.

[self.collectionView reloadData]; 
[self.textField becomeFirstResponder]; 

Кроме того, для меня он отлично работал на симуляторе, но не работал на устройстве.

Настройка контроллера представления как текстовое поле делегат и реализации

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField { 
    return NO; 
} 

не работает, потому что, как вид коллекции результата не обновить. Моя догадка заключается в том, что до перезагрузки коллекции его взглядов пытается удалить фокус из всех вложенных элементов управления, но это невозможно - мы возвращаем NO из метода делегата текстового поля.

Итак, решение для меня состояло в том, чтобы позволить системе удалить фокус из текстового поля, а затем вернуть его после перезагрузки. Вопрос в том, когда на самом деле это делать.

Во-первых, я пытался сделать это в

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 

но когда не было никаких элементов в коллекции (что обычно и бывает во время фильтрации) этот метод не дозвонились.

В конце концов я решил это следующим образом. Я создал подкласс UICollectionReusableView, реализующий два метода: -prepareForReuse и -drawRect :. Первый содержит вызов -setNeedsDesplay, который планирует drawRect вызывать следующий цикл рисования. Второй восстанавливает фокус, вызывая [self.textField статьFirstResponder], если для соответствующего флага установлено значение YES. Таким образом, идея заключалась в том, чтобы называть beFirstResponder «позже», но не слишком поздно, иначе происходит странное «прыжки» клавиатуры.

Мой заказ многоразовые вид коллекции выглядит следующим образом:

@interface MyCollectionReusableView : UICollectionReusableView 

@property (nonatomic, assign) BOOL restoreFocus; 
@property (nonatomic, strong) UITextField *textField; 

@end 


@implementation MyCollectionReusableView 
@synthesize restoreFocus; 
@synthesize textField; 

- (void)setTextField:(UITextField *)value { 
    textField = value; 
    [self addSubview:textField]; 
} 

- (void)drawRect:(CGRect)rect { 
    [super drawRect:rect]; 
    if (self.restoreFocus) { 
     [self.textField becomeFirstResponder]; 
    } 
} 

- (void)prepareForReuse { 
    [self setNeedsDisplay]; 
} 

Тогда в моем View Controller:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    [self.collectionView registerClass:[MyCollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:HeaderReuseIdentifier]; 

    [self.textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged]; 
} 

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { 
    if (UICollectionElementKindSectionHeader == kind) { 
     MyCollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader                   withReuseIdentifier:HeaderReuseIdentifier                     forIndexPath:indexPath]; 

     //add textField to the reusable view 
     if (nil == view.textField) { 
      view.textField = self.textField; 
     } 
     //set restore focus flag to the reusable view 
     view.restoreFocus = self.restoreFocus; 
     self.restoreFocus = NO; 
     return view; 
    } 
    return nil; 
} 

- (void)textFieldDidChange:(UITextField *)textField { 
    self.restoreFocus = YES; 
    [self.collectionView reloadData]; 
} 

Вероятно, не самое элегантное решение, но это работает. :)

+0

Спасибо, я проверю. –

7

В функции searchBar-делегата я использую executeBatchUpdates, во-первых, перезагружаем collectionView, затем вызываем [self.поискBar становитсяFirstResponder] для отображения клавиатуры

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{ 
    [self setEditing:NO animated:YES]; 
    [searchBar setShowsCancelButton:YES animated:YES]; 

     [self.collectionView performBatchUpdates:^{ 
      [self.collectionView reloadData]; 
     } completion:^(BOOL finished) { 
      [self.searchBar becomeFirstResponder]; 
     }]; 
} 
+0

Это должно быть правильно anwser –

+0

Это заслуживает большего количества очков, чем у него –

+0

Собственно, этот ответ наиболее совершенен: http://stackoverflow.com/a/25796944/501439 – GeneCode

0

Ответ заключается в том, чтобы не перезагрузить раздел с текстовым полем. Я решил эту проблему, поставив все элементы в один поиск, чтобы можно было перезагрузить этот отдельный раздел.

Существующий экран, который я изменял, показывал указатель справа с буквами, чтобы перейти к каждому разделу, что означает, что существует много разделов, из-за чего сложнее узнать, как перезагрузить каждый из этих разделов без вмешательства внутреннего состояния , Чтобы заставить его работать, когда текстовое поле становится первым ответчиком, организация изменения коллекции собирает все элементы в один раздел, который перезагружается при запуске поиска . Теперь верхняя часть не перезагружается, поэтому она не теряет фокуса.

Этот способ не требует неопределенного поведения, как и другие ответы, перечисленные для этого вопроса.

https://github.com/brennanMKE/PullDownSearch