Создание прокрутки UITableView при выделении текстового поля - PullRequest
245 голосов
/ 27 февраля 2009

После долгих проб и ошибок я сдаюсь и задаю вопрос. Я видел много людей с похожими проблемами, но не мог правильно ответить на все ответы.

У меня есть UITableView, который состоит из пользовательских ячеек. Ячейки состоят из 5 текстовых полей, расположенных рядом друг с другом (вроде сетки).

Когда я пытаюсь прокрутить и отредактировать ячейки внизу UITableView, мне не удается правильно расположить свои ячейки над клавиатурой.

Я видел много ответов, говорящих об изменении размеров вида и т. Д., Но ни один из них до сих пор не работал должным образом.

Может ли кто-нибудь уточнить «правильный» способ сделать это на конкретном примере кода?

Ответы [ 45 ]

0 голосов
/ 28 июня 2017
// 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 голосов
/ 15 сентября 2012

Я думаю, что нет "правильного" способа сделать это. Вы должны выбрать наиболее подходящее решение для вашего случая использования. В моем приложении для iPad у меня есть UIViewController, который представлен модальным как UIModalPresentationFormSheet и состоит из UITableView. Эта таблица содержит два UITextFields на ячейку. Просто вызов scrollToRowAtIndexPath:atScrollPosition:animated: в методе textFieldDidBeginEditing: не работает для меня. Поэтому я создал tableFooterView:

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

Идея состоит в том, что клавиатура скрывает tableFooterView, а не UITextFields. Так что tableFooterView должно быть достаточно высоким. После этого вы можете использовать scrollToRowAtIndexPath:atScrollPosition:animated: в методе textFieldDidBeginEditing:.

Я думаю, что также возможно динамически отображать и скрывать tableFooterView, добавляя наблюдателей для уведомлений клавиатуры, но я еще не пробовал:

- (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 голосов
/ 02 июля 2016

Посмотрите на мою версию:)

    - (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 голосов
/ 06 июня 2014

Я думаю, что лучший способ - через UITableViewController.

Если вам нужен UITableView в UIViewController , просто создайте ContentView со встроенным UITableViewController и поместите следующие строки в viedDidLoad UIViewController:

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

Легко;)

0 голосов
/ 21 августа 2014

Вот мое решение, вдохновленное экраном «Редактирование событий» из приложения Календарь iOS7.

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

Реализация:

1) Добавьте свойство, которое будет хранить выбранное текстовое поле:

@property (strong) UITextField *currentTextField;

и переменная BOOL, которую мы будем использовать для проверки необходимости скрывать клавиатуру при прокрутке таблицы пользователем.

BOOL hideKeyboardOnScroll;

2) Обработка обратных вызовов делегата UITextField:

#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) Обработайте метод UIScrollViewDelegate, чтобы проверить это представление прокрутки пользователя.

#pragma mark - UIScrollViewDelegate

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

4) Подписаться на уведомления клавиатуры в методе [viewWillAppear] viewcontroller и отписаться в методе [viewWillDisappear].

- (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) Обработка уведомлений клавиатуры:

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