it-swarm.com.de

UITableView-Bildlauf durchführen, wenn Textfeld ausgewählt ist

Nach vielen Versuchen und Irrtümern gebe ich auf und stelle die Frage. Ich habe viele Leute mit ähnlichen Problemen gesehen, kann aber nicht alle Antworten bekommen, um richtig zu arbeiten.

Ich habe eine UITableView, die aus benutzerdefinierten Zellen besteht. Die Zellen bestehen aus 5 nebeneinander liegenden Textfeldern (ähnlich einem Gitter).

Wenn ich versuche, die Zellen am unteren Rand des UITableView zu scrollen und zu bearbeiten, kann ich meine Zellen nicht richtig über der Tastatur positionieren.

Ich habe viele Antworten gesehen, die über das Ändern der Ansichtsgröße usw. sprachen, aber bisher hat keine von ihnen gut funktioniert.

Könnte irgendjemand mit einem konkreten Codebeispiel den "richtigen" Weg klären?

236
Jonathan

Wenn Sie UITableViewController anstelle von UIViewController verwenden, erfolgt dies automatisch.

121
Sam Ho

Die Funktion, die das Scrollen durchführt, könnte wesentlich einfacher sein:

- (void) textFieldDidBeginEditing:(UITextField *)textField {
    UITableViewCell *cell;

    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
    // Load resources for iOS 6.1 or earlier
        cell = (UITableViewCell *) textField.superview.superview;

    } else {
        // Load resources for iOS 7 or later
        cell = (UITableViewCell *) textField.superview.superview.superview; 
       // TextField -> UITableVieCellContentView -> (in iOS 7!)ScrollView -> Cell!
    }
    [tView scrollToRowAtIndexPath:[tView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

Das ist es. Keine Berechnungen.

91
user91083

Ich mache etwas sehr ähnliches es ist generisch, keine Notwendigkeit, etwas spezielles für Ihren Code zu berechnen .. __ Überprüfen Sie einfach die Anmerkungen zum Code:

In MyUIViewController.h

@interface MyUIViewController: UIViewController <UITableViewDelegate, UITableViewDataSource>
{
     UITableView *myTableView;
     UITextField *actifText;
}

@property (nonatomic, retain) IBOutlet UITableView *myTableView;
@property (nonatomic, retain) IBOutlet UITextField *actifText;

- (IBAction)textFieldDidBeginEditing:(UITextField *)textField;
- (IBAction)textFieldDidEndEditing:(UITextField *)textField;

-(void) keyboardWillHide:(NSNotification *)note;
-(void) keyboardWillShow:(NSNotification *)note;

@end

In MyUIViewController.m

@implementation MyUIViewController

@synthesize myTableView;
@synthesize actifText;

- (void)viewDidLoad 
{
    // Register notification when the keyboard will be show
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillShow:)
                                          name:UIKeyboardWillShowNotification
                                          object:nil];

    // Register notification when the keyboard will be hide
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillHide:)
                                          name:UIKeyboardWillHideNotification
                                          object:nil];
}

// To be link with your TextField event "Editing Did Begin"
//  memoryze the current TextField
- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
    self.actifText = textField;
}

// To be link with your TextField event "Editing Did End"
//  release current TextField
- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
    self.actifText = nil;
}

-(void) keyboardWillShow:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    // Start animation
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Reduce size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height -= keyboardBounds.size.height;
    else 
        frame.size.height -= keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    // Scroll the table view to see the TextField just above the keyboard
    if (self.actifText)
      {
        CGRect textFieldRect = [self.myTableView convertRect:self.actifText.bounds fromView:self.actifText];
        [self.myTableView scrollRectToVisible:textFieldRect animated:NO];
      }

    [UIView commitAnimations];
}

-(void) keyboardWillHide:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Increase size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height += keyboardBounds.size.height;
    else 
        frame.size.height += keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    [UIView commitAnimations];
}

@end

Swift 1.2+ Version:

class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var activeText: UITextField!
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillShow:"),
            name: UIKeyboardWillShowNotification,
            object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillHide:"),
            name: UIKeyboardWillHideNotification,
            object: nil)
    }

    func textFieldDidBeginEditing(textField: UITextField) {
        activeText = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        activeText = nil
    }

    func keyboardWillShow(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height -= keyboardSize.height
            tableView.frame = frame
            if activeText != nil {
                let rect = tableView.convertRect(activeText.bounds, fromView: activeText)
                tableView.scrollRectToVisible(rect, animated: false)
            }
            UIView.commitAnimations()
        }
    }

    func keyboardWillHide(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height += keyboardSize.height
            tableView.frame = frame
            UIView.commitAnimations()
        }
    }
}
68
ZeLegolas

Ich hatte das gleiche Problem, bemerkte aber, dass es nur in einer Ansicht erscheint. Also fing ich an, nach den Unterschieden bei den Controllern zu suchen.

Ich habe herausgefunden, dass das Bildlaufverhalten in - (void)viewWillAppear:(BOOL)animated der Superinstanz festgelegt ist.

Stellen Sie also sicher, dass Sie Folgendes implementieren:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // your code
}

Es ist egal, ob Sie UIViewController oder UITableViewController verwenden. hat es überprüft, indem Sie eine UITableView als Unteransicht von self.view in die UIViewController setzen. Es war das gleiche Verhalten. Die Ansicht ließ keinen Bildlauf zu, wenn der Aufruf [super viewWillAppear:animated]; fehlte.

44
ph.dev

Die einfachste Lösung für Swift 3, basierend auf Bartłomiej Semańczyk-Lösung :

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

// MARK: Keyboard Notifications

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
        tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.2, animations: {
        // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
        self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
    })
}
40
squall2022

ich habe das vielleicht verpasst, da ich den ganzen Beitrag hier nicht gelesen habe, aber das, was ich mir ausgedacht habe, scheint täuschend einfach. Ich habe dies nicht in allen Situationen getestet, aber es scheint gut zu funktionieren.

passen Sie einfach das contentInset der Tabellenansicht um die Höhe der Tastatur an und scrollen Sie dann die Zelle nach unten:

- (void)keyboardWasShown:(NSNotification *)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    self.myTableView.contentInset = contentInsets;
    self.myTableView.scrollIndicatorInsets = contentInsets;

    [self.myTableView scrollToRowAtIndexPath:self.currentField.indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}

und natürlich

- (void)keyboardWasHidden:(NSNotification *)aNotification
{
    [UIView animateWithDuration:.3 animations:^(void) 
    {
        self.myTableView.contentInset = UIEdgeInsetsZero;
        self.myTableView.scrollIndicatorInsets = UIEdgeInsetsZero;
    }];
}

ist das zu einfach? verpasse ich etwas bisher klappt es gut für mich, aber wie gesagt, ich habe es nicht durch den Wringer genommen ...

37
mickm

Ich denke, ich habe die Lösung gefunden, um das Verhalten von Apples Apps anzupassen.

Zuerst in Ihrem viewWillAppear: Abonnieren Sie die Tastaturbenachrichtigungen, damit Sie wissen, wann die Tastatur ein- und ausgeblendet wird, und das System die Größe der Tastatur angibt. Vergessen Sie jedoch nicht, die Registrierung in viewWillDisappear: aufzuheben.

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

Implementieren Sie die folgenden Methoden, um die Größe Ihrer tableView an den sichtbaren Bereich anzupassen, sobald die Tastatur angezeigt wird. Hier verfolge ich den Status der Tastatur separat, sodass ich selbst festlegen kann, wann das tableView wieder auf volle Höhe eingestellt werden soll, da Sie diese Benachrichtigungen bei jeder Feldänderung erhalten. Vergessen Sie nicht, keyboardWillHide: zu implementieren, und wählen Sie einen geeigneten Ort, um Ihre tableView-Größe festzulegen.

-(void) keyboardWillShow:(NSNotification *)note
{
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &keyboardBounds];
    keyboardHeight = keyboardBounds.size.height;
    if (keyboardIsShowing == NO)
    {
        keyboardIsShowing = YES;
        CGRect frame = self.view.frame;
        frame.size.height -= keyboardHeight;

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationBeginsFromCurrentState:YES];
        [UIView setAnimationDuration:0.3f];
        self.view.frame = frame;
        [UIView commitAnimations];
    }
}

Hier ist das Bildlauf-Bit, wir arbeiten zunächst einige Größen aus, dann sehen wir, wo wir uns im sichtbaren Bereich befinden, und stellen das Rechteck, das wir scrollen möchten, entweder auf die Halbansicht oberhalb oder unterhalb der Mitte des Textfelds wo es in der Ansicht ist. In diesem Fall verfügen wir über ein Array von UITextFields und eine Enumeration, die den Überblick behält. Wenn Sie also rowHeight mit der Zeilennummer multiplizieren, erhalten Sie den tatsächlichen Versatz des Frames in dieser äußeren Ansicht.

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGRect frame = textField.frame;
    CGFloat rowHeight = self.tableView.rowHeight;
    if (textField == textFields[CELL_FIELD_ONE])
    {
        frame.Origin.y += rowHeight * CELL_FIELD_ONE;
    }
    else if (textField == textFields[CELL_FIELD_TWO])
    {
        frame.Origin.y += rowHeight * CELL_FIELD_TWO;
    }
    else if (textField == textFields[CELL_FIELD_THREE])
    {
        frame.Origin.y += rowHeight * CELL_FIELD_THREE;
    }
    else if (textField == textFields[CELL_FIELD_FOUR])
    {
        frame.Origin.y += rowHeight * CELL_FIELD_FOUR;
    }
    CGFloat viewHeight = self.tableView.frame.size.height;
    CGFloat halfHeight = viewHeight / 2;
    CGFloat midpoint = frame.Origin.y + (textField.frame.size.height / 2);
    if (midpoint < halfHeight)
    {
        frame.Origin.y = 0;
        frame.size.height = midpoint;
    }
    else
    {
        frame.Origin.y = midpoint;
        frame.size.height = midpoint;
    }
    [self.tableView scrollRectToVisible:frame animated:YES];
}

Das scheint ganz gut zu funktionieren.

35
Michael Baltaks

Wenn Sie UITableViewController verwenden können, erhalten Sie die Funktionalität kostenlos. Manchmal ist dies jedoch keine Option, insbesondere wenn Sie mehrere Ansichten und nicht nur die Variable UITableView benötigen.

Einige der hier vorgestellten Lösungen funktionieren nicht auf iOS ≥4, andere nicht auf dem iPad oder im Querformat, andere nicht für Bluetooth-Tastaturen (bei denen kein Scrollen gewünscht wird), andere nicht Arbeit beim Wechseln zwischen mehreren Textfeldern. Wenn Sie sich für eine Lösung entscheiden, stellen Sie sicher, dass Sie diese Fälle testen. Dies ist die Lösung, die wir haben benutzen used in InAppSettingsKit :

- (void)_keyboardWillShow:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        // we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
        NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
        if (!keyboardFrameValue) {
            keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
        }

        // Reduce the tableView height by the part of the keyboard that actually covers the tableView
        CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            windowRect = IASKCGRectSwap(windowRect);
        }
        CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
        }
        CGRect frame = _tableView.frame;
        frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = frame;
        [UIView commitAnimations];

        UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
        NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

        // iOS 3 sends hide and show notifications right after each other
        // when switching between textFields, so cancel -scrollToOldPosition requests
        [NSObject cancelPreviousPerformRequestsWithTarget:self];

        [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
    }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)_keyboardWillHide:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = self.view.bounds;
        [UIView commitAnimations];

        [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
    }
}   

Hier ist der vollständige Code der Klasse in InAppSettingsKit. Um es zu testen, verwenden Sie den untergeordneten Bereich "Complete List", in dem Sie die oben genannten Szenarien testen können.

35
Ortwin Gentz

Die einfachste Lösung für Swift :

override func viewDidLoad() {
    super.viewDidLoad()

    searchBar?.becomeFirstResponder()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillHide(_:)), name: UIKeyboardDidHideNotification, object: nil)
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue.size.height {
            tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    UIView.animateWithDuration(0.2, animations: { self.table_create_issue.contentInset = UIEdgeInsetsMake(0, 0, 0, 0) })
    // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
    }

Ich hoffe, ihr habt schon eine Lösung gefunden. Ich fand meine Lösung jedoch wie folgt. Ich erwarte, dass Sie bereits eine Zelle mit UITextField haben. Behalten Sie beim Vorbereiten einfach den Zeilenindex im Tag des Textfelds.

cell.textField.tag = IndexPath.row;

Erstellen Sie eine activeTextField-Instanz von UITextField mit globalem Gültigkeitsbereich wie folgt: 

@interface EditViewController (){

    UITextField *activeTextField;

}

Jetzt kopieren Sie einfach meinen Code am Ende. Und vergessen Sie nicht, UITextFieldDelegate hinzuzufügen.

#pragma mark - TextField Delegation

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{

    activeTextField = textField;

    return YES;
}

- (void)textFieldDidEndEditing:(UITextField *)textField{

    activeTextField = nil;

}

Registriert Tastatur notifications

#pragma mark - Keyboard Activity

- (void)registerForKeyboardNotifications

{

    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWasShown:)

                                             name:UIKeyboardDidShowNotification object:nil];



    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWillBeHidden:)

                                             name:UIKeyboardWillHideNotification object:nil];



}

Griffe Tastatur Notifications:

Wird aufgerufen, wenn UIKeyboardDidShowNotification gesendet wird.

- (void)keyboardWasShown:(NSNotification*)aNotification

{

    NSDictionary* info = [aNotification userInfo];

    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);

    [self.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

    NSIndexPath *currentRowIndex = [NSIndexPath indexPathForRow:activeTextField.tag inSection:0];

    [self.tableView scrollToRowAtIndexPath:currentRowIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];

}

Wird aufgerufen, wenn UIKeyboardWillHideNotification gesendet wird

- (void)keyboardWillBeHidden:(NSNotification*)aNotification

{

    UIEdgeInsets contentInsets = UIEdgeInsetsZero;

    [self.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

}

Nun bleibt nur noch eines übrig: Rufen Sie die registerForKeyboardNotifications-Methode in der ViewDidLoad-Methode wie folgt auf:

- (void)viewDidLoad {

    [super viewDidLoad];

    // Registering keyboard notification

    [self registerForKeyboardNotifications];

    // Your codes here...

}

Sie sind fertig, ich hoffe, Ihr textFields wird nicht mehr von der Tastatur verborgen.

Durch das Kombinieren und Ausfüllen der Leerzeichen aus mehreren Antworten (insbesondere Ortwin Gentz, Benutzer 98013) und einem anderen Beitrag wird dies für SDK 4.3 auf einem iPad im Hoch- oder Querformat-Modus sofort funktionieren: 

@implementation UIView (FindFirstResponder)
- (UIResponder *)findFirstResponder
{
  if (self.isFirstResponder) {        
    return self;     
  }

  for (UIView *subView in self.subviews) {
    UIResponder *firstResponder = [subView findFirstResponder];
    if (firstResponder != nil) {
      return firstResponder;
    }
  }

  return nil;
}
@end

@implementation MyViewController

- (UIResponder *)currentFirstResponder {
  return [self.view findFirstResponder];
}

- (IBAction)editingEnded:sender {
  [sender resignFirstResponder];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
  [textField resignFirstResponder];
  return NO;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField {
  UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
  [_tableView scrollToRowAtIndexPath:[_tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillShow:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {
    NSDictionary* userInfo = [notification userInfo];

    // we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
    NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
    if (!keyboardFrameValue) {
      keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
    }

    // Reduce the tableView height by the part of the keyboard that actually covers the tableView
    CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
    CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
    CGRect frame = _tableView.frame;
    if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
      windowRect = CGRectMake(windowRect.Origin.y, windowRect.Origin.x, windowRect.size.height, windowRect.size.width);
      viewRectAbsolute = CGRectMake(viewRectAbsolute.Origin.y, viewRectAbsolute.Origin.x, viewRectAbsolute.size.height, viewRectAbsolute.size.width);
    }
    frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = frame;
    [UIView commitAnimations];

    UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
    NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

    // iOS 3 sends hide and show notifications right after each other
    // when switching between textFields, so cancel -scrollToOldPosition requests
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    _topmostRowBeforeKeyboardWasShown = [[_tableView indexPathsForVisibleRows] objectAtIndex:0];
    [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
  }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillHide:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {

    NSDictionary* userInfo = [notification userInfo];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = self.view.bounds;
    [UIView commitAnimations];

    [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
  }
}   

@end
6
Colin

Mein Ansatz:

Ich subclass zuerst UITextField und füge eine indexPath -Eigenschaft hinzu. In der cellFor ... Methode übergebe ich die indexPath -Eigenschaft.

Dann füge ich folgenden Code hinzu:

UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:textField.indexPath];

CGPoint cellPoint = [cell convertPoint:textField.center toView:self.tableView];
[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, cellPoint.y-50);}];

zum textFieldShould/WillBegin ... etc.

Wenn die Tastatur nicht mehr angezeigt wird, müssen Sie sie umkehren:

[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, 0);}];
5
Sven

Wenn Sie Three20 verwenden, verwenden Sie die autoresizesForKeyboard-Eigenschaft. Legen Sie einfach die -initWithNibName:bundle-Methode Ihres View-Controllers fest

self.autoresizesForKeyboard = YES

Dies kümmert sich um:

  1. Auf Tastaturbenachrichtigungen warten und den Rahmen der Tabellenansicht anpassen
  2. Zum ersten Antwortenden blättern

Gemacht und gemacht.

5
Think Top Down

Die richtige Antwort ist Sam Ho's Antwort:

"Wenn Sie UITableViewController anstelle von UIViewController verwenden, geschieht dies automatisch.".

Stellen Sie einfach sicher, dass Sie Ihr UITableView mit der TableView-Eigenschaft des UITableViewController verbinden (fügen Sie es also nicht als Unteransicht der View-Eigenschaft des UITableViewController hinzu).

Stellen Sie außerdem sicher, dass die AutoresizingMask-Eigenschaft Ihres UITableView auf FlexibleHeight festgelegt ist

5
Marcel W

Wenn Sie eine uitableview verwenden, um Ihre Textfelder zu platzieren ( von Jeff Lamarche ), können Sie die Tabellenansicht einfach mit der Delegat-Methode scrollen. 

(Hinweis: Meine Textfelder werden in einem Array mit demselben Index wie die Zeile in der Tabellenansicht gespeichert.)

- (void) textFieldDidBeginEditing:(UITextField *)textField
    {

        int index;
        for(UITextField *aField in textFields){

            if (textField == aField){
                index = [textFields indexOfObject:aField]-1;
            }
        }

         if(index >= 0) 
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];

        [super textFieldDidBeginEditing:textField];
    }
5
Corey Floyd

Tastaturbenachrichtigungen funktionieren, aber Apples Beispielcode dafür setzt voraus, dass die Bildlaufansicht die Stammansicht des Fensters ist. Dies ist normalerweise nicht der Fall. Sie müssen Tabulatoren usw. ausgleichen, um den richtigen Versatz zu erhalten.

Es ist einfacher als es klingt. Hier ist der Code, den ich in einem UITableViewController verwende. Es hat zwei Instanzvariablen, hiddenRect und keyboardShown.

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification {
    if (keyboardShown)
        return;

    NSDictionary* info = [aNotification userInfo];

    // Get the frame of the keyboard.
    NSValue *centerValue = [info objectForKey:UIKeyboardCenterEndUserInfoKey];
    NSValue *boundsValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
    CGPoint keyboardCenter = [centerValue CGPointValue];
    CGRect keyboardBounds = [boundsValue CGRectValue];
    CGPoint keyboardOrigin = CGPointMake(keyboardCenter.x - keyboardBounds.size.width / 2.0,
                                         keyboardCenter.y - keyboardBounds.size.height / 2.0);
    CGRect keyboardScreenFrame = { keyboardOrigin, keyboardBounds.size };


    // Resize the scroll view.
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = scrollView.frame;
    CGRect keyboardFrame = [scrollView.superview convertRect:keyboardScreenFrame fromView:nil];
    hiddenRect = CGRectIntersection(viewFrame, keyboardFrame);

    CGRect remainder, slice;
    CGRectDivide(viewFrame, &slice, &remainder, CGRectGetHeight(hiddenRect), CGRectMaxYEdge);
    scrollView.frame = remainder;

    // Scroll the active text field into view.
    CGRect textFieldRect = [/* selected cell */ frame];
    [scrollView scrollRectToVisible:textFieldRect animated:YES];

    keyboardShown = YES;
}


// Called when the UIKeyboardDidHideNotification is sent
- (void)keyboardWasHidden:(NSNotification*)aNotification
{
    // Reset the height of the scroll view to its original value
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = [scrollView frame];
    scrollView.frame = CGRectUnion(viewFrame, hiddenRect);

    keyboardShown = NO;
}
5
Dustin Voss

Verwenden Sie die UITextField'sdelegate-Methode:

Schnell

func textFieldShouldBeginEditing(textField: UITextField) -> bool {
  let txtFieldPosition = textField.convertPoint(textField.bounds.Origin, toView: yourTableViewHere)
  let indexPath = yourTablViewHere.indexPathForRowAtPoint(txtFieldPosition)
  if indexPath != nil {
     yourTablViewHere.scrollToRowAtIndexPath(indexPath!, atScrollPosition: .Top, animated: true)
  }
  return true
}

Ziel c

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
  CGPoint txtFieldPosition = [textField convertPoint:CGPointZero toView: yourTablViewHere];
  NSLog(@"Begin txtFieldPosition : %@",NSStringFromCGPoint(txtFieldPosition));
  NSIndexPath *indexPath = [yourTablViewHere indexPathForRowAtPoint:txtFieldPosition];

  if (indexPath != nil) {
     [yourTablViewHere scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
  }
  return YES;
}
5
Paresh Navadiya

Eine stromlinienförmigere Lösung. Es wird in die UITextField-Delegatmethoden eingefügt, sodass keine Benachrichtigungen mit UIKeyboard-Benachrichtigungen erforderlich sind.

Implementierungshinweise:

kSettingsRowHeight - die Höhe einer UITableViewCell.

offsetTarget und offsetThreshold werden von kSettingsRowHeight abgesetzt. Wenn Sie eine andere Zeilenhöhe verwenden, setzen Sie diese Werte auf die y-Eigenschaft des Punkts. [alt: Berechne den Zeilenversatz auf eine andere Weise.]

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
CGFloat offsetTarget    = 113.0f; // 3rd row
CGFloat offsetThreshold = 248.0f; // 6th row (i.e. 2nd-to-last row)

CGPoint point = [self.tableView convertPoint:CGPointZero fromView:textField];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];

CGRect frame = self.tableView.frame;
if (point.y > offsetThreshold) {
    self.tableView.frame = CGRectMake(0.0f,
                      offsetTarget - point.y + kSettingsRowHeight,
                      frame.size.width,
                      frame.size.height);
} else if (point.y > offsetTarget) {
    self.tableView.frame = CGRectMake(0.0f,
                      offsetTarget - point.y,
                      frame.size.width,
                      frame.size.height);
} else {
    self.tableView.frame = CGRectMake(0.0f,
                      0.0f,
                      frame.size.width,
                      frame.size.height);
}

[UIView commitAnimations];

return YES;

}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];

CGRect frame = self.tableView.frame;
self.tableView.frame = CGRectMake(0.0f,
                  0.0f,
                  frame.size.width,
                  frame.size.height);

[UIView commitAnimations];

return YES;

}

4
Kelvin

Ich bin auf so etwas wie Ihr Problem gestoßen (ich wollte einen Bildschirm, der den Einstellungen des iPhones ähnelt. App mit einer Reihe bearbeitbarer Zellen, die auf einem anderen gestapelt sind) und stellte fest, dass dieser Ansatz gut funktioniert:

Uitextfelder herumschieben, um zu vermeiden

4
drewh

Da Sie Textfelder in einer Tabelle haben, ist es am besten, die Größe der Tabelle zu ändern. Sie müssen tableView.frame so einstellen, dass es um die Größe der Tastatur kleiner wird (ich denke um 165 Pixel) und es dann wieder erweitern Die Tastatur wird abgewiesen.

Sie können optional auch die Benutzerinteraktion für die tableView deaktivieren, wenn Sie nicht möchten, dass der Benutzer scrollen soll.

Ein Beispiel in Swift, das den genauen Punkt des Textfelds aus Get indexPath von UITextField in UITableViewCell mit Swift verwendet:

func textFieldDidBeginEditing(textField: UITextField) {
    let pointInTable = textField.convertPoint(textField.bounds.Origin, toView: self.accountsTableView)
    let textFieldIndexPath = self.accountsTableView.indexPathForRowAtPoint(pointInTable)
    accountsTableView.scrollToRowAtIndexPath(textFieldIndexPath!, atScrollPosition: .Top, animated: true)
}
2
ginchly

Sehr interessanter Diskussionsfaden, ich habe auch das gleiche Problem konfrontiert

  1. Ich habe eine benutzerdefinierte Zelle verwendet und das Textfeld befand sich darin.
  2. Ich musste UIViewController verwenden, um meine Anforderungen zu erfüllen, so dass UITableViewController nicht genutzt werden kann.
  3. Ich hatte Filter-/Sortierkriterien in meiner Tabellenzelle, dh ur-Zellen ändern sich ständig und behalten den Indexpfad im Auge, und alle helfen nicht.

Lesen Sie also die Threads hier und implementieren Sie meine Version, die mir dabei geholfen hat, meine Inhalte im iPad in landscape mode nach oben zu bringen. Hier ist der Code (dies ist nicht dumm und sicher, aber es hat mein Problem behoben) Zuerst müssen Sie einen Delegaten in Ihrer benutzerdefinierten Zellklasse haben, der bei der Bearbeitung das Textfeld an Ihren Viewcontroller sendet und dort das activefield = theTextField setzt

// NUR DURCHGEFÜHRT, UM DEN LANDSCHAFTSMODUS ZU HANDELN

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbValue = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect aRect = myTable.frame;

    CGSize kbSize = CGSizeMake(kbValue.height, kbValue.width);

    aRect.size.height -= kbSize.height+50;
// This will the exact rect in which your textfield is present
        CGRect rect =  [myTable convertRect:activeField.bounds fromView:activeField];
// Scroll up only if required
    if (!CGRectContainsPoint(aRect, rect.Origin) ) {


            [myTable setContentOffset:CGPointMake(0.0, rect.Origin.y) animated:YES];

    }


}

// Wird aufgerufen, wenn die UIKeyboardWillHideNotification gesendet wird

- (void)keyboardWillHide:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    myTable.contentInset = contentInsets;
    myTable.scrollIndicatorInsets = contentInsets;
    NSDictionary* info = [aNotification userInfo];
    CGSize kbValue = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGSize kbSize = CGSizeMake(kbValue.height, kbValue.width);
    CGRect bkgndRect = activeField.superview.frame;
    bkgndRect.size.height += kbSize.height;
    [activeField.superview setFrame:bkgndRect];
    [myTable setContentOffset:CGPointMake(0.0, 10.0) animated:YES];
}

-anoop4real

2
anoop4real

Ich habe ein solches Problem gerade von mir gelöst, nachdem ich über Google und Stack Overflow eine Vielzahl von Lösungen gefunden hatte.

Stellen Sie zunächst sicher, dass Sie ein IBOutlet für Ihr UIScrollView eingerichtet haben, Dann schauen Sie sich Apple Doc: Keyboard Management ..__ deckt noch die Textfelder ab, bitte sehen Sie sich diesen Code an:

// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;

if (aRect.size.height < activeField.frame.Origin.y+activeField.frame.size.height) {

    CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.Origin.y+activeField.frame.size.height-aRect.size.height);

    [scrollView setContentOffset:scrollPoint animated:YES];

Der Hauptunterschied zwischen diesem Stück und Apples liegt in der if-Bedingung. Ich glaube, Apples Berechnung der Bildlaufentfernung und der Bedingung, ob das durch die Tastatur abgedeckte Textfeld nicht genau ist, habe ich wie oben beschrieben modifiziert.

Lass mich wissen ob es funktioniert

2
dumbfingers

Ich habe fast den gleichen Ansatz ausprobiert und einen einfacheren und kleineren Code für dasselbe entwickelt ..__ Ich habe ein IBOutlet iTextView erstellt und mit dem UITextView in der IB verknüpft.

 -(void)keyboardWillShow:(NSNotification *)notification
    {
        NSLog(@"Keyboard");
        CGRect keyFrame = [[[notification userInfo]objectForKey:UIKeyboardFrameEndUserInfoKey]CGRectValue];

        [UIView beginAnimations:@"resize view" context:nil];
        [UIView setAnimationCurve:1];
        [UIView setAnimationDuration:1.0];
        CGRect frame = iTableView.frame;
        frame.size.height = frame.size.height -  keyFrame.size.height;
        iTableView.frame = frame;
        [iTableView scrollRectToVisible:frame animated:YES];
        [UIView commitAnimations];

    }
2
thesummersign

Dies funktioniert perfekt und auch auf dem iPad.

- (BOOL)textFieldShouldReturn:(UITextField *)textField 
{

    if(textField == textfield1){
            [accountName1TextField becomeFirstResponder];
        }else if(textField == textfield2){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield3 becomeFirstResponder];

        }else if(textField == textfield3){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield4 becomeFirstResponder];

        }else if(textField == textfield4){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield5 becomeFirstResponder];

        }else if(textField == textfield5){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:3 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield6 becomeFirstResponder];

        }else if(textField == textfield6){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:4 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield7 becomeFirstResponder];

        }else if(textField == textfield7){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:5 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield8 becomeFirstResponder];

        }else if(textField == textfield8){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:6 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield9 becomeFirstResponder];

        }else if(textField == textfield9){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:7 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textField resignFirstResponder];
        }
2
WrightsCS

Swift 4.2 Komplettlösung

Ich habe Gist mit einer Reihe von Protokollen erstellt , das die Arbeit mit dem Hinzufügen von Platz erleichtert, wenn die Tastatur angezeigt, ausgeblendet oder geändert wird.

Eigenschaften:

  • Funktioniert korrekt bei Änderungen des Tastaturrahmens (z. B. Änderungen der Tastaturhöhe wie Emojii → normale Tastatur).
  • TabBar & ToolBar-Unterstützung für das UITableView-Beispiel (bei anderen Beispielen erhalten Sie falsche Einfügungen).
  • Dauer der dynamischen Animation (nicht fest codiert).
  • Protokollorientierter Ansatz, der für Ihre Zwecke leicht geändert werden kann.

Verwendungszweck

Grundlegendes Anwendungsbeispiel in View Controller, das einige Bildlauf-Ansichten enthält (Tabellenansicht wird natürlich auch unterstützt).

class SomeViewController: UIViewController {
  @IBOutlet weak var scrollView: UIScrollView!

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    addKeyboardFrameChangesObserver()
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    removeKeyboardFrameChangesObserver()
  }
}

extension SomeViewController: ModifableInsetsOnKeyboardFrameChanges {
  var scrollViewToModify: UIScrollView { return scrollView }
}

Core: Frame wechselt Beobachter

Das Protokoll KeyboardChangeFrameObserver löst jedes Mal ein Ereignis aus, wenn der Tastatur-Frame geändert wurde (einschließlich Anzeigen, Ausblenden, Frame-Wechsel).

  1. Rufen Sie addKeyboardFrameChangesObserver() unter viewWillAppear() oder einer ähnlichen Methode auf.
  2. Rufen Sie removeKeyboardFrameChangesObserver() unter viewWillDisappear() oder einer ähnlichen Methode auf.

Implementierung: Scrolling-Ansicht

Das Protokoll ModifableInsetsOnKeyboardFrameChanges fügt dem Kernprotokoll die Unterstützung von UIScrollView hinzu. Es ändert die Einfügungen der Bildlaufansicht, wenn der Tastaturrahmen geändert wird.

Ihre Klasse muss die Scroll-Ansicht einstellen, die Einfügungen werden bei Frame-Änderungen der Tastatur vergrößert/verkleinert.

var scrollViewToModify: UIScrollView { get }
2
Vasily

Diese Lösung funktioniert für mich, bitte beachten Sie die Zeile

[tableView setContentOffset:CGPointMake(0.0, activeField.frame.Origin.y-kbSize.height+160) animated:YES];

Sie können den Wert 160 ändern, damit er mit Ihnen zusammenarbeitet

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = activeField.superview.frame;
                        bkgndRect.size.height += kbSize.height;
     [activeField.superview setFrame:bkgndRect];
     [tableView setContentOffset:CGPointMake(0.0, activeField.frame.Origin.y-kbSize.height+160) animated:YES];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
   activeField = textField;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
 {
     activeField = nil;
 }
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    tableView.contentInset = contentInsets;
    tableView.scrollIndicatorInsets = contentInsets;
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = activeField.superview.frame;
    //bkgndRect.size.height += kbSize.height;
    [activeField.superview setFrame:bkgndRect];
    [tableView setContentOffset:CGPointMake(0.0, activeField.frame.Origin.y-kbSize.height) animated:YES];
}
2
hiennt

Nach stundenlanger Arbeit, die versucht hatte, diese aktuellen Lösungen zu verwenden (und völlig auszufallen), habe ich endlich die Dinge gut gemacht und sie aktualisiert, um die neuen Animationsblöcke zu verwenden. Meine Antwort basiert vollständig auf der oben genannten Antwort von Ortwin .

Aus irgendeinem Grund funktionierte der obige Code einfach nicht für mich. Mein Setup schien den anderen ziemlich ähnlich zu sein, aber vielleicht, weil ich auf einem iPad oder 4.3 war ... keine Ahnung. Es machte ein bisschen verrückte Mathematik und schoss meine Tischansicht vom Bildschirm ab.

Siehe Endergebnis meiner Lösung: http://screencast.com/t/hjBCuRrPC (Bitte ignorieren Sie das Foto. :-P)

Also habe ich mich mit dem Gist von Ortwin befasst, aber es wurde etwas geändert, um die Origin.y & size.Höhe meiner Tabellenansicht mit der Höhe der Tastatur zusammenzurechnen. Wenn ich die Höhe des Fensters von diesem Ergebnis abziehe, wird mir angezeigt, wie viele Kreuzungen ich habe. Wenn es größer als 0 ist (auch bekannt, da es einige Überlappungen gibt), führe ich die Animation der Framehöhe durch. 

Darüber hinaus gab es einige Probleme beim Neuzeichnen, die gelöst wurden durch: 1) Warten auf Scrollen zur Zelle, bis die Animation abgeschlossen ist, und 2) Verwenden der Option UIViewAnimationOptionBeginFromCurrentState, wenn die Tastatur ausgeblendet wird.

Ein paar Dinge zu beachten. 

  • _topmostRowBeforeKeyboardWasShown & _originalFrame sind im Header deklarierte Instanzvariablen.
  • self.guestEntryTableView ist meine tableView (ich bin in einer externen Datei)
  • IASKCGRectSwap ist die Methode von Ortwin zum Umdrehen der Koordinaten eines Frames
  • Ich aktualisiere die Höhe der tableView nur, wenn mindestens 50px davon angezeigt werden
  • Da ich nicht in einem UIViewController bin, habe ich kein self.view, also kehre ich die tableView in ihren ursprünglichen Rahmen zurück

Wieder wäre ich nicht in die Nähe dieser Antwort gekommen, wenn ich Ortwin nicht den entscheidenden Punkt gegeben hätte. Hier ist der Code:

- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
    self.activeTextField = textField;

    if ([self.guestEntryTableView indexPathsForVisibleRows].count) {
        _topmostRowBeforeKeyboardWasShown = (NSIndexPath*)[[self.guestEntryTableView indexPathsForVisibleRows] objectAtIndex:0];
    } else {
        // this should never happen
        _topmostRowBeforeKeyboardWasShown = [NSIndexPath indexPathForRow:0 inSection:0];
        [textField resignFirstResponder];
    }
}

- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
    self.activeTextField = nil;
}

- (void)keyboardWillShow:(NSNotification*)notification {
    NSDictionary* userInfo = [notification userInfo];

    NSValue* keyboardFrameValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];

    // Reduce the tableView height by the part of the keyboard that actually covers the tableView
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
    CGRect viewRectAbsolute = [self.guestEntryTableView convertRect:self.guestEntryTableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
    CGRect keyboardFrame = [keyboardFrameValue CGRectValue];
    if (UIInterfaceOrientationLandscapeLeft == orientation ||UIInterfaceOrientationLandscapeRight == orientation ) {
        windowRect = IASKCGRectSwap(windowRect);
        viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
        keyboardFrame = IASKCGRectSwap(keyboardFrame);
    }

    // fix the coordinates of our rect to have a top left Origin 0,0
    viewRectAbsolute = FixOriginRotation(viewRectAbsolute, orientation, windowRect.size.width, windowRect.size.height);

    CGRect frame = self.guestEntryTableView.frame;
    _originalFrame = self.guestEntryTableView.frame;

    int remainder = (viewRectAbsolute.Origin.y + viewRectAbsolute.size.height + keyboardFrame.size.height) - windowRect.size.height;

    if (remainder > 0 && !(remainder > frame.size.height + 50)) {
        frame.size.height = frame.size.height - remainder;
        float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        [UIView animateWithDuration: duration
                        animations:^{
                            self.guestEntryTableView.frame = frame;
                        }
                        completion:^(BOOL finished){
                            UITableViewCell *textFieldCell = (UITableViewCell*) [[self.activeTextField superview] superview];
                            NSIndexPath *textFieldIndexPath = [self.guestEntryTableView indexPathForCell:textFieldCell];
                            [self.guestEntryTableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
                        }];
    }

}

- (void)keyboardWillHide:(NSNotification*)notification {
    NSDictionary* userInfo = [notification userInfo];
    float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration: duration
                          delay: 0.0
                        options: (UIViewAnimationOptionBeginFromCurrentState)
                     animations:^{
                         self.guestEntryTableView.frame = _originalFrame;
                     }
                     completion:^(BOOL finished){
                         [self.guestEntryTableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
                     }];

}   

#pragma mark CGRect Utility function
CGRect IASKCGRectSwap(CGRect rect) {
    CGRect newRect;
    newRect.Origin.x = rect.Origin.y;
    newRect.Origin.y = rect.Origin.x;
    newRect.size.width = rect.size.height;
    newRect.size.height = rect.size.width;
    return newRect;
}

CGRect FixOriginRotation(CGRect rect, UIInterfaceOrientation orientation, int parentWidth, int parentHeight) {
    CGRect newRect;
    switch(orientation)
    {
        case UIInterfaceOrientationLandscapeLeft:
            newRect = CGRectMake(parentWidth - (rect.size.width + rect.Origin.x), rect.Origin.y, rect.size.width, rect.size.height);
            break;
        case UIInterfaceOrientationLandscapeRight:
            newRect = CGRectMake(rect.Origin.x, parentHeight - (rect.size.height + rect.Origin.y), rect.size.width, rect.size.height);
            break;
        case UIInterfaceOrientationPortrait:
            newRect = rect;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            newRect = CGRectMake(parentWidth - (rect.size.width + rect.Origin.x), parentHeight - (rect.size.height + rect.Origin.y), rect.size.width, rect.size.height);
            break;
    }
    return newRect;
}
2
Bob Spryn

Wenn Ihre UITableView von einer Unterklasse von UITableViewController und nicht von UITableView verwaltet wird und der Textfelddelegat der UITableViewController ist, sollte er das Scrollen automatisch verwalten. Alle diese Kommentare sind in der Praxis sehr schwer zu implementieren.

Ein gutes Beispiel finden Sie im Apple-Beispielcodeprojekt: TaggedLocations.

Sie können sehen, dass es automatisch scrollt, aber es scheint keinen Code zu geben, der dies tut. Dieses Projekt verfügt auch über benutzerdefinierte Tabellensichtzellen. Wenn Sie also Ihre Anwendung als Leitfaden erstellen, sollten Sie das gewünschte Ergebnis erhalten.

1
shim

Ich benutze diese und sie arbeiten wie ein Zauber:

BSKeyboardControls - BSKeyboardControls github

TPKeyboardAvoiding - TPKeyboardAvoiding github

1
Oskariagon

Ich verwende das oft in meinen Projekten. Diese Lösung funktioniert mit Scroll-Ansichten, Tabellen- oder Sammlungsansichten und ist einfach einzurichten .. __ Sie schließt auch automatisch die Schaltflächen "Weiter" auf der Tastatur an, um zwischen den Textfeldern zu wechseln.

Überprüfen Sie es hier

1
Cristina Sita

Eine andere einfache Methode (funktioniert nur mit einem Abschnitt)

//cellForRowAtIndexPath
UItextField *tf;
[cell addSubview:tf];
tf.tag = indexPath.row;
tf.delegate = self;

//textFieldDidBeginEditing:(UITextField *)text
[[self.tableView scrollToRowsAtIndexPath:[NSIndexPath indexPathForRow:text.tag in section:SECTIONINTEGER] animated:YES];
1
JonasG

Kleine Variante mit Swift 4.2 ...

Auf meinem UITableView hatte ich viele Abschnitte, aber ich musste den Floating-Header-Effekt vermeiden also habe ich einen "dummyViewHeight" -Ansatz verwendet, wie man ihn sonst irgendwo auf Stack Overflow sieht ... Das ist also mein Lösung für dieses Problem (funktioniert auch für Tastatur + Symbolleiste + Vorschläge):

Deklarieren Sie es als Klassenkonstante:

let dummyViewHeight: CGFloat = 40.0

Dann

override func viewDidLoad() {
    super.viewDidLoad()
    //... some stuff here, not needed for this example

    // Create non floating header
    tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: dummyViewHeight))
    tableView.contentInset = UIEdgeInsets(top: -dummyViewHeight, left: 0, bottom: 0, right: 0)

    addObservers()
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    removeObservers()
}

Und hier die ganze Magie ...

@objc func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        let keyboardHeight = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as AnyObject).cgRectValue.size.height
        tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.bounds.size.width, height: dummyViewHeight))
        tableView.contentInset = UIEdgeInsets(top: -dummyViewHeight, left: 0, bottom: keyboardHeight, right: 0)
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.25) {
        self.tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.bounds.size.width, height: self.dummyViewHeight))
        self.tableView.contentInset = UIEdgeInsets(top: -self.dummyViewHeight, left: 0, bottom: 0, right: 0)
    }
}
1
DungeonDev

Einfache und schnelle Lösung.

Ich scrolle einfach in die rechte Zelle, wenn ein Bildlauf stattfindet 

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView 

Angenommen, ich weiß, dass die Tabelle jetzt in diesem Modus "_keepMyCellOnTop" Ist. & Ich kenne die ausgewählte Zelle "_selectedCellIndex" oder scrolle zur ausgewählten Zelle

- (void)scrollViewDidScroll:(UIScrollView *)scrollView 
{

    if (_keepMyCellOnTop)
    {
        [self.tableView scrollToRowAtIndexPath:_selectedCellIndex atScrollPosition:UITableViewScrollPositionTop animated:NO];
    }
}

Dies verhindert das Scrollen.

Wenn Sie den Code in -(void) scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView einfügen, wird ein Bildlauf nach oben und unten durchgeführt 

1
judthedude

UITableViewController führt automatisch einen Bildlauf durch ..__ Der Unterschied zur Verwendung von UIViewController besteht darin, dass Sie Navbar-Buttonitems mithilfe von NavigationController programmgesteuert erstellen müssen, wenn Sie TableViewController verwenden.

1
Tom01

Ich werde meine Lösung (oder QuickDialogs) in den Hut werfen. Warten Sie im Grunde, um das Scrollen zu animieren. Es wäre schön, die Tastaturanimation JIT anstelle der magischen Zahl zu erhalten.

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    if (textField == self.emailTextField) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 50 * USEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
        });
    }
}
1
Steve Moser

So habe ich diese Arbeit gemacht, eine Mischung aus Sam Ho und Marcel Ws Antworten, und einige meiner eigenen Fehlerbehebungen, die ich in meinem beschissenen Code gemacht habe. Ich habe einen UITableViewController verwendet. Die Tabelle ändert sich jetzt korrekt, wenn die Tastatur angezeigt wird.

1) In viewDidLoad habe ich hinzugefügt:

self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight;

2) Ich hatte vergessen, die super-Entsprechungen in viewWillAppear und awakeFromNib zu nennen. Ich habe diese wieder hinzugefügt.

1
Danyal Aytekin

in viewdidload

-(void)viewdidload{

[super viewdidload];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
}

    -(void)keyboardWillChange:(NSNotification*)sender{

        NSLog(@"keyboardwillchange sender %@",sender);

float margin=0  // set your own topmargin


        CGFloat originY = [[sender.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].Origin.y;


        if (originY >= self.view.frame.size.height){

            NSLog(@"keyboardclose");



            [tb_ setFrame:CGRectMake(0, margin, self.view.frame.size.width, self.view.frame.size.height-margin)];

        }else{

            NSLog(@"keyobard on");

            float adjustedHeight = self.view.frame.size.height - margin - (self.view.frame.size.height-originY);

            [tb_ setFrame:CGRectMake(0, margin, self.view.frame.size.width, adjustedHeight)];
        }







    }
1
chings228

Schau dir meine Version an :)

    - (void)keyboardWasShown:(NSNotification *)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = cellSelected.superview.frame;
    bkgndRect.size.height += kbSize.height;
    [cellSelected.superview setFrame:bkgndRect];
    [tableView setContentOffset:CGPointMake(0.0, cellSelected.frame.Origin.y-kbSize.height) animated:YES];
}


- (void)keyboardWasHidden:(NSNotification *)aNotification
{
    [tableView setContentOffset:CGPointMake(0.0, 0.0) animated:YES];
}
0
Pavel

Ich denke, der beste Weg ist durch UITableViewController. 

Wenn Sie ein UITableView in einem UIViewController möchten, erstellen Sie einfach ein ContentView mit einem eingebetteten UITableViewController und fügen Sie die folgenden Zeilen in viedDidLoad des UIViewController ein:

self.tableView = ((UITableViewController*)self.childViewControllers[0]).tableView;
self.tableView.delegate = self;
self.tableView.dataSource = self;

Einfach ;)

0
Ricardo Anjos

Ich habe gerade einen weiteren Fehler bei der Verwendung von UITableViewController entdeckt. Es wurde nicht automatisch gescrollt, als die Tastatur angezeigt wurde. Mir ist aufgefallen, dass es an contentInsetAdjustmentBehavior = .never in UITableView lag.

0

Hier ist meine Lösung, die vom Bildschirm "Ereignisbearbeitung" der iOS7 Kalender-App inspiriert wurde.

Einer der wichtigsten Punkte dieser Lösung ist, dass die Tastatur beim Scrollen durch den Benutzer nicht angezeigt wird.

Implementierung:

1) Fügen Sie eine Eigenschaft hinzu, in der das ausgewählte Textfeld gespeichert wird:

@property (strong) UITextField *currentTextField;

und die BOOL-Variable, mit der geprüft wird, ob die Tastatur ausgeblendet werden muss, wenn der Benutzer die Tabelle durchläuft.

BOOL hideKeyboardOnScroll;

2) Behandeln Sie UITextField-Delegaten-Callbacks:

#pragma mark - UITextFieldDelegate

- (void) textFieldDidBeginEditing: (UITextField *) textField {
    self.currentTextField = textField;
}

- (void) textFieldDidEndEditing: (UITextField *) textField {
    self.currentTextField = nil;
}

- (BOOL) textFieldShouldReturn: (UITextField *) textField {
   [textField resignFirstResponder];

    CGPoint newContentOffset = CGPointZero;
    if (tableView.contentSize.height > tableView.frame.size.height) {
        newContentOffset.y = MIN(tableView.contentOffset.y, tableView.contentSize.height - tableView.frame.size.height);
    }
    [tableView setContentOffset: newContentOffset animated: YES];

    return YES;
}

3) Behandeln Sie die UIScrollViewDelegate-Methode, um diese Ansicht des Benutzers zu überprüfen.

#pragma mark - UIScrollViewDelegate

- (void) scrollViewDidScroll: (UIScrollView *) scrollView {
    if (hideKeyboardOnScroll == YES) {
        [self.currentTextField resignFirstResponder];
    }
}

4) Abonnieren Sie die Tastaturbenachrichtigungen in der Methode [viewWillAppear] von viewcontroller und kündigen Sie sie in der Methode [viewWillDisappear] ab.

- (void) viewWillAppear: (BOOL) animated {
    [super viewWillAppear: animated];

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

- (void) viewWillDisappear: (BOOL) animated {
    [super viewWillDisappear: animated];

    [ [NSNotificationCenter defaultCenter] removeObserver: self name: UIKeyboardDidShowNotification object: nil];
    [ [NSNotificationCenter defaultCenter] removeObserver: self name: UIKeyboardWillHideNotification object: nil];    
}

5) Tastaturbenachrichtigungen behandeln:

- (void) keyboardWillShow: (NSNotification *) notification {
    CGRect keyboardFrame = [ [ [notification userInfo] objectForKey: UIKeyboardFrameBeginUserInfoKey] CGRectValue];

    // Find cell with textfield.
    CGRect textFieldFrame = [tableView convertRect: self.currentTextField.frame fromView: self.currentTextField];
    NSIndexPath *indexPath = [tableView indexPathForRowAtPoint: textFieldFrame.Origin];
    UITableViewCell *cell = [tableView cellForRowAtIndexPath: indexPath];
    //

    // Shrink tableView size.
    CGRect tableViewFrame = tableView.frame;
    tableView.frame = CGRectMake(tableView.frame.Origin.x, tableView.frame.Origin.y, tableView.frame.size.width,
                             self.view.frame.size.height - tableView.frame.Origin.y - keyboardFrame.size.height);
    //

    // Check if cell is visible in shrinked table size.
    BOOL cellIsFullyVisible = YES;
    if ( cell.frame.Origin.y < tableView.contentOffset.y ||
        (cell.frame.Origin.y + cell.frame.size.height) > (tableView.contentOffset.y + tableView.frame.size.height) ) {
        cellIsFullyVisible = NO;
    }
    //

    // If cell is not fully visible when scroll table to show cell;
    if (cellIsFullyVisible == NO) {
        CGPoint contentOffset = CGPointMake(tableView.contentOffset.x, CGRectGetMaxY(cell.frame) - tableView.frame.size.height);
        if (cell.frame.Origin.y < tableView.contentOffset.y) {
            contentOffset.y = cell.frame.Origin.y;
        }
        contentOffset.y = MAX(0, contentOffset.y);

        // For some reason [setContentOffset] is called without delay then
        // this code may not work for some cells. That why we call it with brief delay.
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [UIView animateWithDuration: 0.5 animations:^{
                [tableView setContentOffset: contentOffset animated: NO];
            } completion: ^(BOOL finished) {
                hideKeyboardOnScroll = YES;
            }];
        });
    } else {
        hideKeyboardOnScroll = YES;
    }
    //

    // Finally restore original table frame.
    tableView.frame = tableViewFrame;
    //
}

- (void) keyboardWillHide: (NSNotification *) notification {
    [super keyboardWillHide: notification];

    hideKeyboardOnScroll = NO;
}
0
Igor Kulagin

Ich habe gerade wieder in die iOS 5.0 lib Referenz hineingeschaut und diesen Abschnitt mit dem Titel "Verschieben von Inhalten unter der Tastatur" gefunden: TextAndWebiPhoneOS KeyboardManagement

Ist das seit iOS 5 vielleicht neu? Ich habe noch nicht hineingelesen, weil ich gerade etwas anderes habe, aber vielleicht wissen andere mehr und können mich und andere hier aufklären.

Ersetzt das Apple-Dokument, was hier diskutiert wurde, oder sind die Informationen für Benutzer von iOS 5 SDK noch nützlich?

0

ich habe ein kleines Projekt erstellt, das dieses Problem mit der Tastatur löst. In meinem Fall muss ich nur die Tabellenansicht aktivieren, wenn die Tastatur angezeigt wird.

Hoffe das hilft!

http://git.io/BrH9eQ

Ich denke, dass es keinen "richtigen" Weg gibt, dies zu tun. Sie müssen die am besten geeignete Lösung für Ihren Anwendungsfall auswählen. In meiner iPad App habe ich eine UIViewController, die modal als UIModalPresentationFormSheet dargestellt wird und aus einer UITableView besteht. Diese Tabelle enthält zwei UITextFields pro Zelle. Der Aufruf von scrollToRowAtIndexPath:atScrollPosition:animated: in der textFieldDidBeginEditing:-Methode funktioniert für mich nicht. Deshalb habe ich eine tableFooterView erstellt:

- (void)viewDidLoad
{
    [super viewDidLoad];

    m_footerView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, m_tableView.frame.size.width, 300.0f)];
    [m_footerView setBackgroundColor:[UIColor clearColor]];
    [m_tableView setTableFooterView:m_footerView];
    [m_footerView release];
}

Die Idee ist, dass die Tastatur die tableFooterView und nicht die UITextFields verbirgt. Die tableFooterView muss also hoch genug sein. Danach können Sie scrollToRowAtIndexPath:atScrollPosition:animated: in der textFieldDidBeginEditing:-Methode verwenden.

Ich denke, es ist auch möglich, die tableFooterView dynamisch anzuzeigen und auszublenden, indem die Beobachter für die Tastaturbenachrichtigungen hinzugefügt werden, aber ich habe es noch nicht probiert:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

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

- (void)keyboardWillShow:(NSNotification *)notification 
{
     [m_tableView setTableFooterView:m_footerView];
}

- (void)keyboardWillHide:(NSNotification *)notification 
{
     [m_tableView setTableFooterView:nil];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
0
René Fischer

Lösung für Swift 3-4 mit Animationen und Tastaturwechsel:

Erstellen Sie zuerst einen Bool:

// MARK: - Private Properties
private var isKeyboardShowing = false

Zweitens fügen Sie den System Keyboard-Benachrichtigungen Observer hinzu:

// MARK: - Overriding ViewController Life Cycle Methods
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: .UIKeyboardWillHide, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChangeFrame), name: .UIKeyboardWillChangeFrame, object: nil)
}

Drittens bereiten Sie die Animationsfunktion vor:

func adjustTableViewInsets(keyboardHeight: CGFloat, duration: NSNumber, curve: NSNumber){
    var extraHeight: CGFloat = 0
    if keyboardHeight > 0 {
        extraHeight = 20
        isKeyboardShowing = true
    } else {
        isKeyboardShowing = false
    }

    let contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight + extraHeight, right: 0)
    func animateFunc() {
        //refresh constraints
        //self.view.layoutSubviews()
        tableView.contentInset = contentInset
    }

    UIView.animate(withDuration: TimeInterval(duration), delay: 0, options: [UIViewAnimationOptions(rawValue: UInt(curve))], animations: animateFunc, completion: nil)
}

Fügen Sie dann die Ziel-/Aktionsmethoden (von den Beobachtern aufgerufen) hinzu:

// MARK: - Target/Selector Actions
func keyboardWillShow(notification: NSNotification) {
    if !isKeyboardShowing {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
            let keyboardHeight = keyboardSize.height

            let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
            let curve = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber

            adjustTableViewInsets(keyboardHeight: keyboardHeight, duration: duration, curve: curve)
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
    let curve = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber
    adjustTableViewInsets(keyboardHeight: 0, duration: duration, curve: curve)
}

func keyboardWillChangeFrame(notification: NSNotification) {
    if isKeyboardShowing {
        let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
        let curve = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber

        if let newKeyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            let keyboardHeight = newKeyboardSize.height
            adjustTableViewInsets(keyboardHeight: keyboardHeight, duration: duration, curve: curve)
        }
    }
}

Vergessen Sie nicht, Beobachter in Deinit oder in viewWillDisappear zu entfernen:

deinit {
    NotificationCenter.default.removeObserver(self)
}
0
Jonathan Hoche
// scroll tableview so content ends at the middle of the tableview (out of the way of the keyboard)
CGPoint newContentOffset = CGPointMake(0, [self.tableView contentSize].height - (self.tableView.bounds.size.height / 2));
[self.tableView setContentOffset:newContentOffset animated:YES];
0
NuN

Keine Notwendigkeit irgendwelche Berechnungen, mit dem folgenden Code wird es funktionieren: Dieser Code habe ich in meiner benutzerdefinierten UITableviewcell verwendet. Es funktioniert:

override func viewDidLoad() {
super.viewDidLoad()

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}


func keyboardWillShow(_ notification:Notification) {

if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
    tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
}}


func keyboardWillHide(_ notification:Notification) {

if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
    tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
}}
0
Venkatesh G