2013-03-06 14 views
16

Ho aggiunto un UISearchBar a un UICollectionView e nel delegato searchBar:textDidChange: filtro il mio modello e chiamare [collectionView reloadData]. reloadData (oltre a reloadSection, ecc.) Vuole rimuovere FirstResponder dal campo di testo della barra di ricerca, ignorando la tastiera.Come filtrare UICollectionView e mantenere la tastiera in alto?

Sto cercando di creare un filtro di "aggiornamento in tempo reale" e quindi è fastidioso che la tastiera si spenga dopo ogni carattere digitato.

Qualche idea?

+0

Grazie per questa domanda. – GeneCode

risposta

0

penso che si sta chiamando il metodo -resignFirstResponder nel delegato searchbar che causano ogni volta che si entra il valore che viene respinto

Sei in strada giusta sui metodi DataSource e ricaricare data.Use un array per memorizzare tutti i valori un altro array per caricare la collectionview e ogni lettera inserita nel filtro della barra di ricerca e caricare l'array di datasource e quindi ricaricare

Beh penso che sia meglio mantenere la tastiera. Quello è lo stile UI giusto dopo che sei dopo aver inserito il testo da cercare, puoi chiuderlo manualmente. Penso che sia l'opzione migliore per un filtro di aggiornamento in tempo reale.

Se si utilizza un pulsante per cercare allora si può includere l'opzione della tastiera nascondere there.but l'aggiornamento in diretta non può essere attuato quando si utilizza tale opzione

0

Ho appena creato una piccola applicazione di test. Il seguente codice non nasconde la tastiera durante l'immissione di caratteri nella barra di ricerca. Detto questo, [UITableView reloadData] non si dimette dal risponditore.

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

Sei sicuro, non ti stai dimettendo da qualche parte?

3

Se hai aggiunto il UISearchBar come intestazione alla UICollectionView la chiamata reloadData si "aggiorna" l'intestazione rimuovendo e re-aggiungendo il UISearchBar facendole perdere firstResponder.

È possibile aggiungere il UISearchBar in un altro modo, non si utilizza intestazione, o ignorare reloadData, controllare se la barra di ricerca è attualmente firstResponder, e in tal caso dopo aver chiamato super, fai:

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

Bella spiegazione. Ma mi chiedo perché TableView non soffra di questo problema. – GeneCode

0

Ecco come lo gestito. Ho avuto il mio UISearchBar come vista supplementare dell'intestazione nella mia vista dell'insieme.Su didchange di testo per il delegato searchbar ho impostato un flag che la ricerca è attiva (o meno) e ricaricato il CollectionView

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

Poi nel cellForItemAtIndexPath verifico se la tastiera è il primo responder e di ricerca è attiva, se non , faccio first responder:

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

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

ho appena aggiunto

[searchBar becomeFirstResponder]; 

dopo aver chiamato

0.123.
[collectionView reloadData]; 
2

risolto:

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

mi imbatto nello stesso problema da poco e ci sono voluti un po 'per farlo riparare. Il problema è che quando il campo di testo è annidato in ReusableCollectionView il seguente non funziona.

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

Inoltre, per me ha funzionato bene sul simulatore ma non ha funzionato sul dispositivo.

Impostazione vista controller come campo di testo delegato e attuazione

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

non ha funzionato perché, come la vista collezione risultato non aggiornare. La mia ipotesi è - prima di ricaricare la sua collezione di viste si tenta di rimuovere l'attenzione da tutti i controlli annidati, ma non può farlo - restituiamo NO dal metodo del delegato del campo di testo.

Quindi la soluzione per me era lasciare che il sistema rimuovesse lo stato attivo dal campo di testo, ma poi recuperarlo dopo averlo ricaricato. La domanda era quando effettivamente farlo.

In primo luogo, ho cercato di farlo nel

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

ma quando non c'erano articoli in collezione (che è caso normale durante la filtrazione) questo metodo non ha ottenuto chiamato.

Eventualmente ho risolto questo nel modo seguente. Ho creato la sottoclasse UICollectionReusableView che implementa due metodi: -prepareForReuse e -drawRect :. Il primo contiene la chiamata -setNeedsDesplay che pianifica la chiamata drawRect al successivo ciclo di disegno. Il secondo ripristina l'attenzione chiamando [self.textField becomeFirstResponder] se il flag corrispondente è impostato su YES. Quindi l'idea era di chiamare diventato prima "Rispondi" ma non troppo tardi, altrimenti si verifica un "salto" strano della tastiera.

mia abitudine vista di raccolta riutilizzabile assomiglia a questo:

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

Poi nel mio 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]; 
} 
non

Probabilmente la soluzione più elegante, ma funziona. :)

+0

Grazie, lo controllerò. –

7

Nella funzione del delegato della funzione di ricerca, uso performBatchUpdates, in primo luogo, ricarica collectionView, quindi chiama [self.SearchBar becomeFirstResponder] per visualizzare la tastiera

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

Questo dovrebbe essere il giusto analogo –

+0

Questo merita più uptotes di quello che ha –

+0

In realtà, questa risposta è la più perfetta: http://stackoverflow.com/a/25796944/501439 – GeneCode

0

La risposta è di non caricare la sezione che ha il campo di testo. Ho risolto questo problema inserendo tutti gli elementi in una singola ricerca, quindi è stato possibile ricaricare quella singola sezione.

La schermata esistente che stavo modificando stava mostrando l'indice sulla destra con le lettere per navigare in ciascuna sezione, il che significa che c'erano molte sezioni che rendono più difficile sapere come ricaricare ciascuna di queste sezioni senza fare confusione con lo stato interno . Per farlo funzionare quando il campo di testo diventa il primo risponditore, l'organizzazione della vista raccolta cambia per posizionare tutti gli elementi in una singola sezione che viene ricaricata quando viene eseguita la ricerca . Ora la parte superiore non viene ricaricata, quindi non perde la concentrazione.

In questo modo non è necessario un comportamento non definito come le altre risposte elencate per questa domanda.

https://github.com/brennanMKE/PullDownSearch

Problemi correlati