Deshabilitar el desplazamiento automático de UITableView al editar UITextField dentro de UITableViewCell


Estoy usando custom UITableViewCell s dentro de mi UITableView. Cada uno de estos UITableViewCell s es bastante alto y contiene un UITextField en la parte superior.

Cuando un usuario toca el UITextField para editarlo, aparece un teclado y el UITableView se desplaza automáticamente para que la celda esté en la parte superior de la pantalla.

El problema es que esto desplaza el UITableView a la parte inferior del UITableViewCell, no a la parte superior. Cuando el UITableViewCell es alto y editado el UITextField está en la parte superior por lo que no se puede ver el UITextField. Sé cómo desplazar el UITableView programáticamente, pero simplemente no sé cómo desactivar este desplazamiento automático para que pueda desplazarse por el UITableView por mi cuenta. ¿Cómo puedo hacer esto?

Author: Bono, 2012-03-09

8 answers

El comportamiento de desplazamiento automático se encuentra en la funcionalidad UITableViewController.

Para desactivar el desplazamiento automático encontré dos maneras:

  1. Use en lugar de UITableViewController simplemente un UIViewController - establezca el origen de datos y delegue por su cuenta.
  2. Sobrescribe el método viewWillAppear y no llame a [super viewWillAppear: animated]

Con ambas soluciones desactiva no solo el Auto-Roll, sino también algunas otras características agradables pero no esenciales, que se describen en la descripción general de la clase Apples referencia:

Https://developer.apple.com/documentation/uikit/uitableviewcontroller

 62
Author: Dominic Sander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-29 14:23:56

Definir propiedades para su UITableViewController:

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

Antes de llamar becomeFirstResponder:

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

Agregue el siguiente código a su controlador de vista de tabla:

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

Después de llamar a resignFirstResponder, establezca scrollDisabled = NO.

 6
Author: william-yang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-01 19:06:34

Puedes hacer lo siguiente:

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

Luego implementa este método UIScrollViewDelegate

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

!!! Pero tenga cuidado, que si el usuario toca en una ubicación en el UITextField que será cubierto por el teclado, entonces no se desplazará.

Desde mi punto de vista, lo mejor que puede hacer es asegurarse de que todas las celdas desde la parte superior hasta una con el UITextField incluido, sean visibles cuando se muestre el teclado.

 3
Author: arturgrigor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-12 13:52:07

El problema para mí no era tanto que se desplaza, sino que tomó la vista de texto está editado fuera de la pantalla.

Así que en lugar de evitar el desplazamiento, simplemente vuelvo a desplazar la vista de tabla a donde quiero cuando se activa la edición, así:

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
Author: infinite-loop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-27 22:33:24

Desafortunadamente, overriding-viewWillAppear: no funciona para mí en iOS 8.

Aquí está mi solución (como en la implementación de UITableViewController):

- (void)viewDidLoad {

[super viewDidLoad];

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

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

Dado que el comportamiento de desplazamiento automático es invocado por las notificaciones mostrar/ocultar de UIKeyboard, por lo que simplemente NO las observe.

 1
Author: keyOfVv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-03 08:10:53

La mejor manera es subclase UITableView y, a continuación, reemplazar setContentOffset(_ contentOffset: CGPoint, animated: Bool) y no llamar super.setContentOffset(_ contentOffset: CGPoint, animated: Bool). En este método es donde el controlador de vista está haciendo el desplazamiento automático.

override func setContentOffset(_ contentOffset: CGPoint, animated: Bool)
{
    //Do nothing
}
 1
Author: juanelomx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-15 17:50:21

¿Ha intentado establecer la propiedad "scrollsToTop" - tableview en NO. Por defecto es SÍ.

 -2
Author: cocoakomali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-10 16:20:20

Puedes intentar hacer lo siguiente:

self.tableView.scrollEnabled = NO;

Esto debería desactivar la vista de desplazamiento en la vista de tabla.

 -5
Author: DHShah01,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-24 01:52:56