2013-03-06 3 views
16

J'ai ajouté un UISearchBar à un UICollectionView et dans le délégué searchBar:textDidChange: filtre mon modèle et appelle [collectionView reloadData]. reloadData (ainsi que reloadSection, etc) veut enlever firstResponder du champ de texte de la barre de recherche, annulant ainsi le clavier. J'essaie de créer un filtre de "mise à jour en direct" et il est donc ennuyeux de faire disparaître le clavier après chaque caractère tapé.Comment filtrer UICollectionView et maintenir le clavier?

Des idées?

+0

Merci d'avoir posé cette question. – GeneCode

Répondre

0

Je pense que vous appelez la méthode -resignFirstResponder dans le délégué searchbar qui provoquent à chaque fois que vous entrez la valeur qu'il obtient rejeté

Vous êtes dans le droit chemin sur les méthodes de DataSource et rechargerez data.Use un tableau pour stocker toutes les valeurs un autre tableau pour charger le collectionview et sur chaque lettre entrée sur le filtre de la barre de recherche et charger le tableau de sources de données, puis recharger

Eh bien, je pense qu'il est préférable de garder le clavier .C'est le bon style d'interface utilisateur après que vous êtes fait entrer le texte pour rechercher vous pouvez le rejeter manuellement. Je pense que c'est la meilleure option pour un filtre de mise à jour en direct.

Si vous utilisez ne peut pas être mis en œuvre un bouton pour rechercher, vous pouvez inclure l'option de masquage du clavier there.but la mise à jour en direct lors de l'utilisation d'une telle option

0

Je viens de créer une petite application de test. Le code suivant ne masque pas le clavier lors de la saisie des caractères dans la barre de recherche. Cela dit, [UITableView reloadData] ne démissionne pas du répondeur.

- (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]; 
} 

Etes-vous sûr que vous ne le quittez pas quelque part?

3

Si vous avez ajouté le UISearchBar en-tête au UICollectionView l'appel reloadData sera « rafraîchir » l'en-tête en supprimant et en rajoutant le UISearchBar faisant perdre firstResponder.

Vous pouvez ajouter votre UISearchBar d'une autre manière, ne pas utiliser en-tête, ou passer outre reloadData, vérifiez si la barre de recherche est actuellement firstResponder, et si oui après avoir appelé super, faites:

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

Belle explication. Mais je me demande pourquoi TableView ne souffre pas de ce problème. – GeneCode

0

Voici comment je réussi. J'avais mon UISearchBar comme vue supplémentaire d'en-tête dans ma vue de collection.Le texte didchange pour le délégué searchbar je mis un drapeau que la recherche est active (ou non) et rechargées le CollectionView

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

Puis, dans la cellForItemAtIndexPath je vérifie si le clavier est le premier répondeur et la recherche est active, sinon , je fais premier répondeur:

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

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

Je viens d'ajouter

[searchBar becomeFirstResponder]; 

après avoir appelé

[collectionView reloadData]; 
2

a résolu le problème:

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

je rencontre le même problème récemment et il a fallu un certain temps pour le faire réparer. Le problème est que lorsque le champ de texte est imbriqué dans ReusableCollectionView, les éléments suivants ne fonctionnent pas. En outre, pour moi cela a bien fonctionné sur le simulateur mais n'a pas fonctionné sur l'appareil.

Réglage contrôleur de vue en tant que délégué du champ de texte et la mise en œuvre

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

ne fonctionne pas parce que la vue de la collecte des résultats n'a pas actualisé. Ma conjecture est - avant de recharger ses collections de vues essaye de retirer le foyer de tous les contrôles imbriqués mais il ne peut pas - nous renvoyons NON de la méthode de délégué de champ de texte. Donc, la solution pour moi était de laisser le système retirer le focus du champ de texte, mais le récupérer après le rechargement. La question était de savoir quand le faire.

D'abord, je l'ai essayé de le faire dans le

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

mais quand il n'y avait pas d'articles dans la collection (qui est le cas normal pendant le filtrage), cette méthode n'a pas s'appeler.

Finalement, j'ai résolu ceci de la façon suivante. J'ai créé la sous-classe UICollectionReusableView en implémentant deux méthodes: -prepareForReuse et -drawRect :. Le premier contient l'appel -setNeedsDesplay qui planifie l'appel drawRect au cycle de dessin suivant. Le second restaure le focus en appelant [self.textField becomeFirstResponder] si l'indicateur correspondant est défini sur YES. Donc, l'idée était d'appeler "getFirstResponder" plus tard, mais pas trop tard, sinon le "saut" bizarre du clavier se produit.

Ma coutume vue de collection réutilisable ressemble à ceci:

@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]; 
} 

Puis dans mon 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]; 
} 

Probablement pas la solution la plus élégante, mais il fonctionne. :)

+0

Merci, je vais vérifier. –

7

Dans la fonction searchBar delegate, j'utilise performBatchUpdates, d'abord, rechargez collectionView puis appelez [self.SearchBar becomeFirstResponder] pour afficher le clavier

- (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

Cela devrait être la bonne réponse –

+0

Cela mérite plus de votes positifs que ce qu'il a –

+0

En fait, cette réponse est la plus parfaite: http://stackoverflow.com/a/25796944/501439 – GeneCode

0

La réponse est de ne pas recharger la section qui a le champ de texte. J'ai résolu ce problème en plaçant tous les éléments dans une recherche unique de sorte qu'il était possible de recharger cette seule section.

L'écran que je modifiais présentait l'index sur la droite avec les lettres pour naviguer vers chaque section, ce qui signifie qu'il y avait beaucoup de sections qui rendent plus difficile de savoir comment recharger chacune de ces sections sans perturber l'état interne . Pour que cela fonctionne lorsque le champ de texte devient le premier répondeur, l'organisation de la vue de collection change pour placer tous les éléments dans une seule section qui est rechargée lorsque la recherche est exécutée. Maintenant, la section du haut n'est pas rechargée pour ne pas perdre le focus.

De cette manière, aucun comportement indéfini n'est nécessaire comme les autres réponses répertoriées pour cette question.

https://github.com/brennanMKE/PullDownSearch

Questions connexes