it-swarm.com.ru

Отключение автоматической прокрутки UITableView при редактировании UITextField внутри UITableViewCell

Я использую пользовательские UITableViewCellname__s внутри своего UITableViewname__. Каждый из этих UITableViewCellname__s довольно высокий и содержит UITextFieldвверху.

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

Проблема заключается в том, что при этом прокручивается UITableViewв нижнюю часть UITableViewCellname__, а не в верхнюю. Когда значение UITableViewCellвысокое и отредактировано, UITextFieldнаходится сверху, поэтому вы не можете видеть UITextFieldname__. Я знаю, как прокручивать UITableViewпрограммно, но я просто не знаю, как отключить эту автоматическую прокрутку, чтобы я мог прокручивать UITableViewсамостоятельно. Как я могу это сделать?

51
animal_chin

Поведение автопрокрутки находится в функциональности UITableViewController.

Чтобы отключить автоматическую прокрутку я нашел два способа:

  1. Используйте вместо UITableViewController просто UIViewController - установите источник данных и делегируйте его самостоятельно.
  2. Переопределите метод viewWillAppear и не вызывайте [super viewWillAppear: animated]

В обоих решениях вы отключаете не только автопрокрутку, но и некоторые другие приятные, но не важные функции, которые описаны в обзоре класса Apple:

https://developer.Apple.com/documentation/uikit/uitableviewcontroller

66
Dominic Sander

Определите свойства для вашего UITableViewController:

@property (nonatomic) BOOL scrollDisabled;
@property (nonatomic) CGFloat lastContentOffsetY;

Прежде чем позвонить becomeFirstResponder:

// Save the table view's y content offset 
lastContentOffsetY = tableViewController.tableView.contentOffset.y;
// Enable scrollDisabled
scrollDisabled = YES;

Добавьте следующий код в ваш контроллер табличного представления:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (self.scrollDisabled) {
        [self.tableView setContentOffset:CGPointMake(0, lastContentOffsetY)];
    }
    ...
}

После вызова resignFirstResponder установите scrollDisabled = NO.

8
william-yang

Вы можете сделать следующее:

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification object:nil];

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

- (void)unregisterForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil];
}

- (void)keyboardWillShow:(NSNotification *)notification
{
    self.tableView.scrollEnabled = NO;
}

- (void)keyboardDidShow:(NSNotification *)notification
{
    double delayInSeconds = 0.3;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            self.tableView.scrollEnabled = YES;
    });
}

Затем реализуйте этот метод UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (! self.tableView.scrollEnabled)
        [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
}

!!! Но имейте в виду, что если пользователь коснется места в UITextField, которое будет закрыто клавиатурой, то оно не будет прокручиваться.

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

4
arturgrigor

Для меня проблема была не столько в том, что он прокручивался, сколько в том, что текстовое представление редактировалось с экрана.

Таким образом, вместо предотвращения прокрутки, я просто переназначаю табличное представление туда, куда я хочу, когда начинается редактирование, например так:

public func textViewShouldBeginEditing(textView: UITextView) -> Bool {            
  dispatch_async(dispatch_get_main_queue()) {
    tableViewController.tableView.scrollToRowAtIndexPath(self.indexPath!, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)
  }
  return true
}
1
infinite-loop

К сожалению, переопределение -viewWillAppear: у меня не работает в iOS 8.

Вот мое решение (как в реализации UITableViewController):

- (void)viewDidLoad {

[super viewDidLoad];

[[NSNotificationCenter defaultCenter] removeObserver:self.tableView name:UIKeyboardWillShowNotification object:nil];

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

Поскольку поведение автоматической прокрутки вызывается уведомлениями UIKeyboard о показе/скрытии, просто НЕ наблюдайте за ними.

1
keyOfVv

Лучший способ - создать подкласс UITableView, а затем переопределить setContentOffset(_ contentOffset: CGPoint, animated: Bool), а не вызывать super.setContentOffset(_ contentOffset: CGPoint, animated: Bool). В этом методе контроллер представления выполняет автоматическую прокрутку.

override func setContentOffset(_ contentOffset: CGPoint, animated: Bool)
{
    //Do nothing
}
1
juanelomx