2012-12-12 10 views
10

Ho cercato molto per il codice che ridimensiona la vista tabella per consentire la visualizzazione e l'occultamento della tastiera, ma quasi ogni singolo post che ho trovato presuppone che la vista tabella stia prendendo l'intera vista della sua vista controller. Ho un'applicazione per iPad in cui la vista tabella sta prendendo solo parte dello schermo. Qual è il modo corretto per ridimensionare la vista tabella in questo caso? (Tutto il codice nei post che ho citato sopra non riesce)Algoritmo di ridimensionamento tastiera UITableView generico

+4

Non hai menzionato alcun codice che non riesce. – Mundi

+0

Perché non regolare il codice che hai trovato per tenere conto della differenza tra la parte inferiore del riquadro di visualizzazione tabella e il riquadro di visualizzazione completa? – Anton

risposta

17

Il seguente codice fa quello che vuoi e funziona con qualsiasi dispositivo e qualsiasi layout. Il codice è per gentile concessione dello Sensible TableView framework (con il permesso di copiare e utilizzare).

- (void)keyboardWillShow:(NSNotification *)aNotification 
{ 
if(keyboardShown) 
    return; 

keyboardShown = YES; 

// Get the keyboard size 
UIScrollView *tableView; 
if([self.tableView.superview isKindOfClass:[UIScrollView class]]) 
    tableView = (UIScrollView *)self.tableView.superview; 
else 
    tableView = self.tableView; 
NSDictionary *userInfo = [aNotification userInfo]; 
NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]; 
CGRect keyboardRect = [tableView.superview convertRect:[aValue CGRectValue] fromView:nil]; 

// Get the keyboard's animation details 
NSTimeInterval animationDuration; 
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; 
UIViewAnimationCurve animationCurve; 
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; 

// Determine how much overlap exists between tableView and the keyboard 
CGRect tableFrame = tableView.frame; 
CGFloat tableLowerYCoord = tableFrame.origin.y + tableFrame.size.height; 
keyboardOverlap = tableLowerYCoord - keyboardRect.origin.y; 
if(self.inputAccessoryView && keyboardOverlap>0) 
{ 
    CGFloat accessoryHeight = self.inputAccessoryView.frame.size.height; 
    keyboardOverlap -= accessoryHeight; 

    tableView.contentInset = UIEdgeInsetsMake(0, 0, accessoryHeight, 0); 
    tableView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, accessoryHeight, 0); 
} 

if(keyboardOverlap < 0) 
    keyboardOverlap = 0; 

if(keyboardOverlap != 0) 
{ 
    tableFrame.size.height -= keyboardOverlap; 

    NSTimeInterval delay = 0; 
    if(keyboardRect.size.height) 
    { 
     delay = (1 - keyboardOverlap/keyboardRect.size.height)*animationDuration; 
     animationDuration = animationDuration * keyboardOverlap/keyboardRect.size.height; 
    } 

    [UIView animateWithDuration:animationDuration delay:delay 
         options:UIViewAnimationOptionBeginFromCurrentState 
        animations:^{ tableView.frame = tableFrame; } 
        completion:^(BOOL finished){ [self tableAnimationEnded:nil finished:nil contextInfo:nil]; }]; 
} 
} 

- (void)keyboardWillHide:(NSNotification *)aNotification 
{ 
if(!keyboardShown) 
    return; 

keyboardShown = NO; 

UIScrollView *tableView; 
if([self.tableView.superview isKindOfClass:[UIScrollView class]]) 
    tableView = (UIScrollView *)self.tableView.superview; 
else 
    tableView = self.tableView; 
if(self.inputAccessoryView) 
{ 
    tableView.contentInset = UIEdgeInsetsZero; 
    tableView.scrollIndicatorInsets = UIEdgeInsetsZero; 
} 

if(keyboardOverlap == 0) 
    return; 

// Get the size & animation details of the keyboard 
NSDictionary *userInfo = [aNotification userInfo]; 
NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]; 
CGRect keyboardRect = [tableView.superview convertRect:[aValue CGRectValue] fromView:nil]; 

NSTimeInterval animationDuration; 
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; 
UIViewAnimationCurve animationCurve; 
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; 

CGRect tableFrame = tableView.frame; 
tableFrame.size.height += keyboardOverlap; 

if(keyboardRect.size.height) 
    animationDuration = animationDuration * keyboardOverlap/keyboardRect.size.height; 

[UIView animateWithDuration:animationDuration delay:0 
        options:UIViewAnimationOptionBeginFromCurrentState 
       animations:^{ tableView.frame = tableFrame; } 
       completion:nil]; 
} 

- (void) tableAnimationEnded:(NSString*)animationID finished:(NSNumber *)finished contextInfo:(void *)context 
{ 
// Scroll to the active cell 
if(self.activeCellIndexPath) 
{ 
    [self.tableView scrollToRowAtIndexPath:self.activeCellIndexPath atScrollPosition:UITableViewScrollPositionNone animated:YES]; 
    [self.tableView selectRowAtIndexPath:self.activeCellIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; 
} 
} 

Note:

a. I due metodi sopra riportati sono stati aggiunti al centro di notifica utilizzando il seguente codice:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; 
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; 

b. Gli ivar usati sopra sono stati dichiarati in questo modo:

BOOL keyboardShown; 
CGFloat keyboardOverlap; 

c. 'self.activeCellIndexPath' è sempre impostato su indexPath della cella proprietaria del UITextField/UITextView attualmente attivo.

Divertiti! :)

+2

Questo è fantastico! funziona come un fascino, grazie mille! – Matt

+0

Vorrei aggiungere solo un'aggiunta. Se l'altezza di UITableViewCell può essere maggiore della dimensione rimasta per presentare UITableView, è meglio modificare il metodo tableAnimationEnded in modo che scorra su "TOP" anziché "NONE". Inoltre, se si presenta la tastiera alla selezione di una cella e si è già gestita la selezione di UITableView, non è necessario selezionare nuovamente "activeCellIndexPath". – Lubakis

1

Check out this project, è trascinare e rilasciare quindi basta dichiarare il tablview come tipo TPKeyboardAvoidingTableView

2

Soluzione semplice - registrarsi per ricevere le notifiche della tastiera su init o viewDidLoad con:

[[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(keyboardWillShow:) 
              name:UIKeyboardWillShowNotification 
             object:nil]; 
[[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(keyboardWillHide:) 
              name:UIKeyboardWillHideNotification 
             object:nil]; 

poi quando si riceve la notifica, è possibile utilizzare la data rect della tastiera per regolare la struttura del vostro tableView:

- (void)keyboardWillShow:(NSNotification *)notification 
{ 
    // Get the size of the keyboard. 
    CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; 

    CGRect newTableFrame = _myTableView.frame; 
    //Here make adjustments to the tableview frame based on the value in keyboard size 
    ... 

    _myTableView.frame = newTableFrame; 
} 

- (void)keyboardWillHide:(NSNotification *)notification 
{ 
    //Here change the table frame back to what it originally was. 
} 
+2

Vorrei suggerire di registrarsi in viewWillAppear: e annullare la registrazione in viewWillDisappear: (a causa di osservatore del centro di notifica che mantiene e perché viewDidUnload: (per annullare la registrazione) è deprecato da iOS 6) – JakubKnejzlik

6

ho trovato la soluzione più semplice per essere questa (io non sono fan di utilizzare subviews per questo genere di cose):

registro per la tastiera cambiamento telaio notifica (idealmente registrarsi in viewWillAppear: e annullare la registrazione in viewWillDisappear :):

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil]; 

e poi nel metodo:

- (void)keyboardDidChangeFrame:(NSNotification*)aNotification 
{ 
    NSDictionary* info = [aNotification userInfo]; 
    UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; 
    CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; 
    CGRect kbIntersectFrame = [window convertRect:CGRectIntersection(window.frame, kbFrame) toView:self.scrollView]; 
    kbIntersectFrame = CGRectIntersection(self.bounds, kbIntersectFrame); 

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbIntersectFrame.size.height, 0.0); 
    self.scrollView.contentInset = contentInsets; 
    self.scrollView.scrollIndicatorInsets = contentInsets; 
} 

o se si vuole sbarazzarsi del "salto" dopo aver cambiato contentInset:

- (void)keyboardDidChangeFrame:(NSNotification*)aNotification 
{ 
    NSDictionary* info = [aNotification userInfo]; 
    UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; 
    CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; 
    CGRect kbIntersectFrame = [window convertRect:CGRectIntersection(window.frame, kbFrame) toView:self.scrollView]; 
    kbIntersectFrame = CGRectIntersection(self.scrollView.bounds, kbIntersectFrame); 

    // get point before contentInset change 
    CGPoint pointBefore = self.scrollView.contentOffset; 
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbIntersectFrame.size.height, 0.0); 
    self.scrollView.contentInset = contentInsets; 
    self.scrollView.scrollIndicatorInsets = contentInsets; 
    // get point after contentInset change 
    CGPoint pointAfter = self.scrollView.contentOffset; 
    // avoid jump by settings contentOffset 
    self.scrollView.contentOffset = pointBefore; 
    // and now animate smoothly 
    [self.scrollView setContentOffset:pointAfter animated:YES]; 
} 
+0

Funziona molto bene ed è più semplice di quello di Tarek sopra. Non scrivo usando la UIWindow, ma dovrebbe essere facilmente passato alla vista, no? – Brian

+1

Sì, in teoria. Tieni a mente che le coordinate della tastiera sono in "dimensioni della finestra", quindi se la vista non ha la stessa dimensione/posizione della finestra, non potrebbe funzionare correttamente. – JakubKnejzlik

3

La soluzione più semplice è quella di aggiungere la mia estensione UIViewController+Keyboard.swift al progetto, con una singola linea setupKeyboardNotifcationListenerForScrollView(tableView) sarà ridimensionamento automatico automaticamente. Non c'è bisogno di sottoclasse nulla, solo un'estensione!La sua open source a SingleLineKeyboardResize

0

Ecco il metodo di tastiera:

func keyboardControl(notification: NSNotification, isShowing: Bool) { 
    var userInfo = notification.userInfo! 
    let keyboardRect = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue 
    let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey]!.unsignedIntValue 

    let convertedFrame = self.view.convertRect(keyboardRect, fromView: nil) 
    let heightOffset = self.view.bounds.size.height - convertedFrame.origin.y 
    let options = UIViewAnimationOptions(rawValue: UInt(curve) << 16) 
    let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey]!.doubleValue 

    //your UITableView bottom constrant 
    self.tableViewMarginBottomConstraint.constant = heightOffset 

    var contentInsets = UIEdgeInsetsZero 
    if isShowing { 
     contentInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardRect.size.height), 0.0) 
    } 

    UIView.animateWithDuration(
     duration, 
     delay: 0, 
     options: options.union(.LayoutSubviews).union(.BeginFromCurrentState), 
     animations: { 
      self.listTableView.contentInset = contentInsets 
      self.listTableView.scrollIndicatorInsets = contentInsets 
      self.listTableView.scrollBottomToLastRow() 
      self.view.layoutIfNeeded() 
     }, 
     completion: { bool in 
    }) 
} 

Qui è l'estensione UITableView:

extension UITableView { 
    func totalRows() -> Int { 
     var i = 0 
     var rowCount = 0 
     while i < self.numberOfSections { 
      rowCount += self.numberOfRowsInSection(i) 
      i++ 
     } 
     return rowCount 
    } 

    var lastIndexPath: NSIndexPath { 
     get { return NSIndexPath(forRow: self.totalRows()-1, inSection: 0) } 
    } 

    func scrollBottomToLastRow() { 
     self.scrollToRowAtIndexPath(self.lastIndexPath, atScrollPosition: .Bottom, animated: false) 
    } 
} 
0

si può ottenere quello che stai cercando utilizzando IQKeyboardManager, è un libreria codeless, devi solo aggiungerla al tuo Podfile: pod 'IQKeyboardManager' e il gioco è fatto, passerà l'effetto di scorrimento quando viene mostrata la tastiera anche se UITextField/UITextView non fa parte di scrollView/tableView.

Problemi correlati