Desabilitar a rolagem do UIScrollView quando o UITextField se torna o primeiro respondedor

Quando um UITextField , incorporado em um UIScrollView se torna o primeiro respondedor, digamos que o usuário digita algum caractere, o UIScrollView rola para esse campo automaticamente, existe alguma maneira de desabilitar isso?

Rdar duplicado: // 16538222 acima

Com base na resposta de Moshe …

Subclass UIScrollView e substitua o seguinte método:

 - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated 

Deixe vazio. Tarefa concluída!

Eu tenho lutado com o mesmo problema e finalmente encontrei uma solução.

Eu investiguei como o scroll automático é feito, rastreando o rastreamento de chamadas, e descobri que um [UIFieldEditor scrollSelectionToVisible] é chamado quando uma letra é digitada no UITextField . Este método parece atuar no UIScrollView do ancestral mais próximo do UITextField .

Portanto, em textFieldDidBeginEditing , agrupando o UITextField com um novo UIScrollView com o mesmo tamanho (isto é, inserindo a visualização entre o UITextField e sua superview), isso bloqueará a rolagem automática. Por fim, remova esse wrapper em textFieldDidEndEditing .

O código é como:

 - (void)textFieldDidBeginEditing:(UITextField*)textField { UIScrollView *wrap = [[[UIScrollView alloc] initWithFrame:textField.frame] autorelease]; [textField.superview addSubview:wrap]; [textField setFrame:CGRectMake(0, 0, textField.frame.size.width, textField.frame.size.height)]; [wrap addSubview: textField]; } - (void)textFieldDidEndEditing:(UITextField*)textField { UIScrollView *wrap = (UIScrollView *)textField.superview; [textField setFrame:CGRectMake(wrap.frame.origin.x, wrap.frame.origin.y, wrap.frame.size.width, textField.frame.size.height)]; [wrap.superview addSubview:textField]; [wrap removeFromSuperview]; } 

espero que isto ajude!

Eu tive o mesmo problema com a desativação da rolagem automática de um UITextView sendo uma célula do UITableView . Consegui resolvê-lo usando a seguinte abordagem:

 @interface MyTableViewController : UITableViewController @implementation MyTableViewController { BOOL preventScrolling; // ... } // ... set self as the delegate of the text view - (void)textViewDidBeginEditing:(UITextView *)textView { preventScrolling = YES; } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (preventScrolling) { [self.tableView setContentOffset:CGPointMake(0, -self.tableView.contentInset.top) animated:NO]; } } - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { preventScrolling = NO; } 

Definir scrollViewWillBeginDragging é usado para restaurar o comportamento de rolagem padrão, quando o próprio usuário inicia a rolagem.

Como Taketo mencionou, quando um UITextField é UITextField como primeiro socorrista, sua primeira exibição pai que é do tipo UIScrollView (se existir) é rolada para tornar esse UITextField visível. O truque mais fácil é simplesmente agrupar cada UITextField em um UIScrollView (ou, idealmente, agrupar todos eles em um único UIScrollView fictício). Isso é muito semelhante à solução da Taketo, mas deve dar a você um desempenho um pouco melhor e manterá seu código (ou sua interface no Interface Builder) muito mais limpo na minha opinião.

Parece UIScrollview que contém UITextfield, auto ajusta seu deslocamento de conteúdo; quando o campo de texto vai se tornar o primeiro respondedor. Isso pode ser resolvido adicionando primeiro o campo de texto na vista de rolagem do mesmo tamanho e, em seguida, adicionando a visualização de rolagem principal. em vez de adicionar diretamente ao scrollview principal

  // Swift let rect = CGRect(x: 0, y: 0, width: 200, height: 50) let txtfld = UITextField() txtfld.frame = CGRect(x: 0, y: 0, width: rect.width, height: rect.height) let txtFieldContainerScrollView = UIScrollView() txtFieldContainerScrollView.frame = rect txtFieldContainerScrollView.addSubview(txtfld) // Now add this txtFieldContainerScrollView in desired UITableViewCell, UISCrollView.. etc self.mainScrollView.addSubview(txtFieldContainerScrollView) // Am33T 

Com base na resposta de Luke, para lidar com o problema de que a solução dele desativa completamente o scroll automático, você pode desativá-lo seletivamente da seguinte maneira:

 // TextFieldScrollView #import  @interface TextFieldScrollView : UIScrollView @property (assign, nonatomic) IBInspectable BOOL preventAutoScroll; @end @implementation TextFieldScrollView - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated { if (self.preventAutoScroll == NO) { [super scrollRectToVisible:rect animated:animated]; } } @end 

Dessa forma, você pode configurá-lo completamente no Interface Builder para desativar a rolagem automática, mas ter controle total a qualquer momento para reativá-lo (embora o motivo pelo qual você queira está além de mim).

É assim que eu faço:

É muito simples, você pode retornar seu próprio contentOffset para qualquer scrollRectToVisible.

Dessa forma, você não está prejudicando o comportamento normal e o stream das coisas – apenas fornecendo a mesma funcionalidade no mesmo canal, com suas próprias melhorias.

 #import  @protocol ExtendedScrollViewDelegate  - (CGPoint)scrollView:(UIScrollView*)scrollView offsetForScrollingToVisibleRect:(CGRect)rect; @end @interface ExtendedScrollView : UIScrollView @property (nonatomic, unsafe_unretained) id scrollToVisibleDelegate; @end #import "ExtendedScrollView.h" @implementation ExtendedScrollView - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated { if (_scrollToVisibleDelegate && [_scrollToVisibleDelegate respondsToSelector:@selector(scrollView:offsetForScrollingToVisibleRect:)]) { [self setContentOffset:[_scrollToVisibleDelegate scrollView:self offsetForScrollingToVisibleRect:rect] animated:animated]; } else { [super scrollRectToVisible:rect animated:animated]; } } @end 

Eu tentei resposta @ TaketoSano, mas parece não funciona .. Meu caso é que eu não tenho um scrollview, apenas uma visão com vários campos de texto.

E finalmente, eu tenho uma solução alternativa. Existem dois nomes de notificação padrão para o teclado que eu preciso:

  • UIKeyboardDidShowNotification quando o teclado foi exibido;
  • UIKeyboardWillHideNotification quando o teclado irá se esconder.

Aqui está o código de amostra que usei:

 - (void)viewDidLoad { [super viewDidLoad]; ... NSNotificationCenter * notificationCetner = [NSNotificationCenter defaultCenter]; [notificationCetner addObserver:self selector:@selector(_keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; [notificationCetner addObserver:self selector:@selector(_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } - (void)_keyboardWasShown:(NSNotification *)note { [self.view setFrame:(CGRect){{272.f, 55.f}, {480.f, 315.f}}]; } - (void)_keyboardWillHide:(NSNotification *)note { [self.view setFrame:(CGRect){{272.f, 226.5f}, {480.f, 315.f}}]; } 

Aqui, o (CGRect){{272.f, 226.5f}, {480.f, 315.f}} é o frame padrão da visão quando o teclado está oculto. E (CGRect){{272.f, 55.f}, {480.f, 315.f}} é o frame da vista quando o teclado é exibido.

E, a mudança de quadro da visão será aplicada automaticamente, isso é realmente perfeito!

Eu tenho uma visão de coleção com um campo de texto no topo, imitando o UITableView.tableHeaderView . Este campo de texto está localizado no espaço de deslocamento do conteúdo negativo, para que não interfira no restante da exibição da coleção. Eu basicamente estou detectando se o usuário está ou não realizando a rolagem na visualização de rolagem e se o campo de texto é ou não primeiro respondedor e se a visualização de rolagem está sendo rolada além da parte superior do conteúdo inserido da visualização de rolagem. Esse código exato não ajuda necessariamente ninguém, mas eles podem manipulá-lo para se adequar ao caso deles.

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { // This is solving the issue where making the text field first responder // automatically scrolls the scrollview down by the height of the search bar. if (!scrollView.isDragging && !scrollView.isDecelerating && self.searchField.isFirstResponder && (scrollView.contentOffset.y < -scrollView.contentInset.top)) { [scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, -scrollView.contentInset.top) animated:NO]; } } 

Não conheço nenhuma propriedade do UIScrollView que permita isso. Seria má experiência do usuário para poder desabilitar isso, IMHO.

Dito isso, pode ser possível subclassificar o UIScrollView e replace alguns de seus methods para verificar se o campo UITextfield não é o primeiro a responder antes de rolar a UITextfield .

Uma maneira mais fácil de parar a rolagem da rolagem quando você seleciona um textField está em sua viewController :: viewWillAppear () NÃO chame [super viewWillAppear];

Você pode controlar o pergaminho como desejar.