Get UITableView to scroll to the selected UITextField and Avoid Being Hidden by Keyboard

后端 未结 13 976
鱼传尺愫
鱼传尺愫 2020-11-29 17:47

I have a UITextField in a table view on a UIViewController (not a UITableViewController). If the table view is on a UITableViewC

相关标签:
13条回答
  • 2020-11-29 18:22

    In my case my UITableview was inside another UIView and that UIvie was in the main UIScrollview. So I used more general solution for those kind of problems. I simply found the Y coordinate of my cell in the specific UIScrollView and then scrolled to correct point:

    -(void)textFieldDidBeginEditing:(UITextField *)textField{
    float kbHeight = 216;//Hard Coded and will not support lanscape mode
    UITableViewCell *cell = (UITableViewCell *)[textField superview];
    float scrollToHeight = [self FindCordinate:cell];
    [(UIScrollView *)self.view setContentOffset:CGPointMake(0, scrollToHeight - kbHeight + cell.frame.size.height) animated:YES];
    }
    
    -(float)FindCordinate:(UIView *)cell{
    float Ycordinate = 0.0;
    while ([cell superview] != self.view) {
        Ycordinate += cell.frame.origin.y;
        cell = [cell superview];
    }
    Ycordinate += cell.frame.origin.y;
    return Ycordinate;
    }
    
    0 讨论(0)
  • 2020-11-29 18:24

    For the sake of anyone else running into this issue, I'm posting the necessary methods here:

    - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
        NSString *identifier = [NSString stringWithFormat: @"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]];
    
        UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier];
    
        if (cell == nil) {
    
            cell = [[[UITableViewCell alloc]  initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
    
            UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];
    
            theTextField.keyboardType = UIKeyboardTypeDefault;
            theTextField.returnKeyType = UIReturnKeyDone;
            theTextField.clearsOnBeginEditing = NO;
            theTextField.textAlignment = UITextAlignmentLeft;
    
            // (The tag by indexPath.row is the critical part to identifying the appropriate
            // row in textFieldDidBeginEditing and textFieldShouldEndEditing below:)
    
            theTextField.tag=indexPath.row;
    
            theTextField.delegate = self;
    
            theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
            [theTextField setEnabled: YES];
    
            [cell addSubview:theTextField];
    
            [theTextField release];
    
        }
    
        return cell;
    }
    
    -(void) textFieldDidBeginEditing:(UITextField *)textField {
    
        int z = textField.tag;                                              
    
        if (z > 4) {
    
            // Only deal with the table row if the row index is 5 
            // or greater since the first five rows are already 
            // visible above the keyboard   
    
            // resize the UITableView to fit above the keyboard
    
            self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,200.0);       
    
            // adjust the contentInset
    
            wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10);        
    
            // Scroll to the current text field
    
            [wordsTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:z inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
    
        }
    }
    
    
    - (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    
        // Determine which row is being edited
    
        int z = textField.tag;  
    
        if (z > 4) {
    
            // resize the UITableView to the original size
    
            self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,416.0);       
    
            // Undo the contentInset
            wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);         
    
        }
    
        return YES;
    
    }
    
    - (BOOL)textFieldShouldReturn:(UITextField *)textField {
    
        // Dismisses the keyboard when the "Done" button is clicked
    
        [textField resignFirstResponder];
    
        return YES;                                 
    
    }
    
    0 讨论(0)
  • 2020-11-29 18:24

    You can try adding a UITableViewController to the UIViewController instead of just a table view. This way you can call UITableViewController's viewWillAppear and everything will appear to work.

    Example:

    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        [tableViewController viewWillAppear:animated];
    }
    
    0 讨论(0)
  • 2020-11-29 18:28

    Swift

    @objc private func keyboardWillShow(_ notification: Notification) {
        guard let userinfo = notification.userInfo else {
            return
        }
    
        guard
            let duration = (userinfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue,
            let endFrame = (userinfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
            let curveOption = userinfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt else {
                return
        }
        
        UIView.animate(withDuration: duration, delay: 0, options: [.beginFromCurrentState, .init(rawValue: curveOption)], animations: {
            let edgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: endFrame.height, right: 0)
            self.scrollView.contentInset = edgeInsets
            self.scrollView.scrollIndicatorInsets = edgeInsets
        })
    }
    
    @objc private func keyboardWillHide(_ notification: Notification) {
        guard let userinfo = notification.userInfo else {
            return
        }
    
        guard
            let duration = (userinfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue,
            let curveOption = userinfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt else {
                return
        }
        
        UIView.animate(withDuration: duration, delay: 0, options: [.beginFromCurrentState, .init(rawValue: curveOption)], animations: {
            let edgeInsets = UIEdgeInsets.zero
            self.scrollView.contentInset = edgeInsets
            self.scrollView.scrollIndicatorInsets = edgeInsets
        })
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // ...
    
        subscribeToKeyboardNotifications()
    }
    
    deinit {
        unsubscribeFromKeyboardNotifications()
    }
    
    private func subscribeToKeyboardNotifications() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIWindow.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIWindow.keyboardWillHideNotification, object: nil)
    }
    
    private func unsubscribeFromKeyboardNotifications() {
        NotificationCenter.default.removeObserver(self, name: UIWindow.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.removeObserver(self, name: UIWindow.keyboardWillHideNotification, object: nil)
    }
    

    Objective C

    - (void)keyboardWillShow:(NSNotification *)sender
    {
        CGFloat height = [[sender.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
        NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;
        
        [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
            UIEdgeInsets edgeInsets = UIEdgeInsetsMake(0, 0, height, 0);
            tableView.contentInset = edgeInsets;
            tableView.scrollIndicatorInsets = edgeInsets;
        } completion:nil];
    }
    
    - (void)keyboardWillHide:(NSNotification *)sender
    {
        NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;
    
        [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
            UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
            tableView.contentInset = edgeInsets;
            tableView.scrollIndicatorInsets = edgeInsets;
        } completion:nil];
    }
    

    And in - (void)viewDidLoad

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

    Then

    - (void)dealloc
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    
    0 讨论(0)
  • 2020-11-29 18:28

    Apple has an official post explaining how to do this naturally as they do in the UITableViewController. My Stackoverflow answer has this explained along with a swift version.

    https://stackoverflow.com/a/31869898/1032179

    0 讨论(0)
  • 2020-11-29 18:31

    You need to resize the tableView itself so that it does not go under the keyboard.

    -(void) textFieldDidBeginEditing:(UITextField *)textField {
    
    // SUPPOSEDLY Scroll to the current text field
    self.worldsTableView.frame = CGRectMake(//make the tableView smaller; to only be in the area above the keyboard);
    CGRect textFieldRect = [textField frame];
    [self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];
    
    }
    

    Alternatively, you can use a keyboard notification; this works slightly better because you have more information, and is more consistent in terms of knowing when the keyboard is coming up:

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

    And then implement:

    - (void)keyboardWillShow:(NSNotification *)notification {
    
    }
    - (void)keyboardWillHide:(NSNotification *)notification {
    
    }
    
    0 讨论(0)
提交回复
热议问题