Получить UITableView, чтобы прокрутить до выбранного UITextField и избежать быть скрытым с помощью клавиатуры - PullRequest
46 голосов
/ 10 марта 2011

У меня есть UITextField в табличном представлении на UIViewController (не UITableViewController). Если табличное представление находится на UITableViewController, таблица автоматически прокручивается до редактируемого textField, чтобы предотвратить его скрытие клавиатурой. Но на UIViewController это не так.

Я несколько дней пытался прочитать несколько способов, чтобы попытаться выполнить это, и я не могу заставить его работать. Самая близкая вещь, которая фактически прокручивает, является:

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

// SUPPOSEDLY Scroll to the current text field

CGRect textFieldRect = [textField frame];
[self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];

}

Однако это только прокручивает таблицу до самого верхнего ряда. То, что кажется легкой задачей, было несколько дней разочарования.

Я использую следующее для построения ячеек таблицы:

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

        cell.accessoryType = UITableViewCellAccessoryNone;

        UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];

        theTextField.adjustsFontSizeToFitWidth = YES;
        theTextField.textColor = [UIColor redColor];
        theTextField.text = [textFieldArray objectAtIndex:indexPath.row];
        theTextField.keyboardType = UIKeyboardTypeDefault;
        theTextField.returnKeyType = UIReturnKeyDone;
        theTextField.font = [UIFont boldSystemFontOfSize:14];
        theTextField.backgroundColor = [UIColor whiteColor];
        theTextField.autocorrectionType = UITextAutocorrectionTypeNo;
        theTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
        theTextField.clearsOnBeginEditing = NO;
        theTextField.textAlignment = UITextAlignmentLeft;

        //theTextField.tag = 0;
        theTextField.tag=indexPath.row;

        theTextField.delegate = self;

        theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
        [theTextField setEnabled: YES];

        [cell addSubview:theTextField];

        [theTextField release];


}

return cell;
}

Я подозреваю, что смогу заставить tableView правильно прокрутиться, если смогу каким-то образом передать indexPath.row в методе textFieldDidBeginEditing?

Любая помощь приветствуется.

Ответы [ 13 ]

108 голосов
/ 11 марта 2011

В моем приложении я успешно использовал комбинацию contentInset и scrollToRowAtIndexPath, например:

Если вы хотите отобразить клавиатуру, просто добавьте contentInset внизу таблицы с нужной высотой:

tableView.contentInset =  UIEdgeInsetsMake(0, 0, height, 0);

Тогда вы можете безопасно использовать

[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:cell_index inSection:cell_section] animated:YES];

При добавлении contentInset, даже если вы фокусируете внимание на последней ячейке, tableView все равно сможет прокручивать. Просто убедитесь, что когда вы закрываете клавиатуру, вы сбрасываете contentInset.

EDIT:
Если у вас есть только один раздел (вы можете заменить cell_section на 0) и использовать тег textView для информирования строки ячейки.

Проверьте это для Прокрутите UITextField над клавиатурой в UITableView ИЛИ UIScrollView

46 голосов
/ 26 августа 2012
- (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];
}

А в - (void) viewDidLoad

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

Тогда

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
10 голосов
/ 11 июля 2013

Это твик к ответу FunkyKat (большое спасибо FunkyKat!). Вероятно, было бы полезно не жестко кодировать UIEdgeInsetsZero для будущей совместимости с iOS.

Вместо этого я запрашиваю текущее значение вставки и при необходимости настраиваю нижнее значение.

- (void)keyboardWillShow:(NSNotification *)sender {
    CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.height : kbSize.width;
    if (isIOS8()) height = kbSize.height;

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = [[self tableView] contentInset];
        edgeInsets.bottom = height;
        [[self tableView] setContentInset:edgeInsets];
        edgeInsets = [[self tableView] scrollIndicatorInsets];
        edgeInsets.bottom = height;
        [[self tableView] setScrollIndicatorInsets:edgeInsets];
    }];
}

- (void)keyboardWillHide:(NSNotification *)sender {
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = [[self tableView] contentInset];
        edgeInsets.bottom = 0;
        [[self tableView] setContentInset:edgeInsets];
        edgeInsets = [[self tableView] scrollIndicatorInsets];
        edgeInsets.bottom = 0;
        [[self tableView] setScrollIndicatorInsets:edgeInsets];
    }];
}
8 голосов
/ 12 марта 2011

Ради всех, кто сталкивается с этой проблемой, я выкладываю здесь необходимые методы:

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

}
1 голос
/ 24 октября 2017

Мне нужно было простое решение, поэтому для меня помогло :

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        let pointInTable = textField.superview!.convert(textField.frame.origin, to: tableView)
        var tableVContentOffset = tableView.contentOffset
        tableVContentOffset.y = pointInTable.y
        if let accessoryView = textField.inputAccessoryView {
            tableVContentOffset.y -= accessoryView.frame.size.height
        }
        tableView.setContentOffset(tableVContentOffset, animated: true)
        return true;
    }

enter image description here

1 голос
/ 07 августа 2015

У Apple есть официальное сообщение, объясняющее, как сделать это естественным образом, как это делается в UITableViewController. Мой ответ в Stackoverflow объяснил это вместе с быстрой версией.

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

1 голос
/ 08 апреля 2013

Попробуйте мою кодировку, это поможет для ypu

tabelview.contentInset =  UIEdgeInsetsMake(0, 0, 210, 0);
[tableview scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:your_indexnumber inSection:Your_section]
                 atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
0 голосов
/ 03 марта 2015

Я добавил небольшую функцию к ответам @FunkyKat и @bmauter (кстати, отличный ответ должен быть принятым)

Обычные вставки краев табличного представления сохраняются до / после клавиатурыЯвление.

- (void)keyboardWillShow:(NSNotification *)sender
{
    CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = self.tableView.contentInset;
        edgeInsets.bottom += height;
        self.tableView.contentInset = edgeInsets;
        edgeInsets = self.tableView.scrollIndicatorInsets;
        edgeInsets.bottom += height;
        self.tableView.scrollIndicatorInsets = edgeInsets;
    }];
}

- (void)keyboardWillHide:(NSNotification *)sender
{
    CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = self.tableView.contentInset;
        edgeInsets.bottom -= height;
        self.tableView.contentInset = edgeInsets;
        edgeInsets = self.tableView.scrollIndicatorInsets;
        edgeInsets.bottom -= height;
        self.tableView.scrollIndicatorInsets = edgeInsets;
    }];
}
0 голосов
/ 13 августа 2014

Вы можете попробовать добавить UITableViewController в UIViewController вместо просто табличного представления.Таким образом, вы можете вызвать UITableViewController viewWillAppear, и все будет работать.

Пример:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [tableViewController viewWillAppear:animated];
}
0 голосов
/ 25 апреля 2014

Другое простое решение - добавление дополнительного пробела для нижнего колонтитула последней секции таблицы:

- (float)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
    if (section == lastSection) {
        return keyboard height;
    }
    return 0;
}

Мы также можем добавить нашу иконку в эту область. :)

...