it-swarm.com.ru

Отключите прокрутку UIScrollView, когда UITextField становится первым респондентом

Когда UITextField, встроенный в UIScrollView, становится первым респондентом, скажем, если пользователь вводит какой-то символ, UIScrollView автоматически прокручивает это поле, есть ли способ отключить это?

Дубликат rdar: // 16538222 более

58
Rabih

Опираясь на ответ Моше ...

Подкласс UIScrollView и переопределить следующий метод:

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

Оставь это пустым. Работа выполнена!

59
Luke

Я боролся с той же проблемой, и, наконец, я нашел решение.

Я исследовал, как выполняется автоматическая прокрутка путем отслеживания трассировки вызовов, и обнаружил, что внутренний [UIFieldEditor scrollSelectionToVisible] вызывается, когда буква вводится в UITextField. Этот метод, кажется, действует на UIScrollView ближайшего предка UITextField.

Таким образом, в textFieldDidBeginEditing, обернув UITextField новым UIScrollView с таким же размером (то есть вставив представление между UITextField и его суперпредставлением), это заблокирует автопрокрутку. Наконец удалите эту обертку на textFieldDidEndEditing.

Код выглядит так:

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

надеюсь это поможет!

53
Taketo Sano

У меня была та же проблема с отключением автоматической прокрутки UITextView, являющегося ячейкой UITableView. Я смог решить это, используя следующий подход:

@interface MyTableViewController : UITableViewController<UITextViewDelegate>

@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;
}

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

7
tonso

Как упомянул Taketo, когда UITextField становится первым респондентом, его первое родительское представление, имеющее тип UIScrollView (если оно существует), прокручивается, чтобы сделать UITextField видимым. Самый простой способ - просто обернуть каждый UITextField в UIScrollView (или, в идеале, обернуть все их в один фиктивный UIScrollView). Это очень похоже на решение Taketo, но оно должно дать вам немного лучшую производительность, и, на мой взгляд, оно сделает ваш код (или ваш интерфейс в Interface Builder) намного чище.

5
danbretl

Похоже, UIScrollview, который содержит UITextfield, автоматически корректирует смещение его содержимого; когда текстовое поле станет первым респондентом . Это можно решить, добавив текстовое поле в виде прокрутки того же размера, а затем добавив его к основному виду прокрутки. вместо непосредственного добавления в основной вид прокрутки

    // 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
2
Amit Tandel

Основываясь на ответе Люка, для решения вопроса о том, что его решение полностью отключает автопрокрутку, вы можете выборочно отключить его следующим образом:

//  TextFieldScrollView
#import <UIKit/UIKit.h>

@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

Таким образом, вы можете полностью настроить его в Интерфейсном Разработчике, чтобы отключить автопрокрутку, но в любое время иметь полный контроль для его повторного включения (хотя, почему вы захотите, мне не под силу).

2
mbm29414

Вот как я это делаю:

Это очень просто, вы можете вернуть свой собственный contentOffset для любого scrollRectToVisible. 

Таким образом, вы не наносите вреда нормальному поведению и потоку вещей - просто предоставляя одинаковые функциональные возможности в том же канале со своими собственными улучшениями.

#import <UIKit/UIKit.h>

@protocol ExtendedScrollViewDelegate <NSObject>

- (CGPoint)scrollView:(UIScrollView*)scrollView offsetForScrollingToVisibleRect:(CGRect)rect;

@end

@interface ExtendedScrollView : UIScrollView

@property (nonatomic, unsafe_unretained) id<ExtendedScrollViewDelegate> 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
1
daniel.gindi

У меня есть представление коллекции с текстовым полем в самом верху, имитирующим UITableView.tableHeaderView. Это текстовое поле расположено в области отрицательного смещения содержимого, поэтому оно не мешает остальной части представления коллекции. Я в основном определяю, выполняет ли пользователь прокрутку в представлении прокрутки и является ли текстовое поле первым респондентом, и прокручивается ли представление прокрутки за верхнюю часть вставки содержимого представления прокрутки. Этот точный код не обязательно поможет никому, но они могут манипулировать им, чтобы соответствовать своему случаю.

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

Я попробовал ответ @ TaketoSano, но, похоже, не работает .. В моем случае у меня нет прокрутки, только вид с несколькими текстовыми полями.

И наконец, я нашел обходной путь. Для клавиатуры есть два названия уведомлений по умолчанию: 

  • UIKeyboardDidShowNotification когда клавиатура показала; 
  • UIKeyboardWillHideNotification когда клавиатура скроется.

Вот пример кода, который я использовал:

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

Здесь (CGRect){{272.f, 226.5f}, {480.f, 315.f}} является рамкой представления по умолчанию, когда клавиатура скрыта. И (CGRect){{272.f, 55.f}, {480.f, 315.f}} - это кадр вида, когда клавиатура показывала.

И, кстати, при смене кадра вида автоматически применяется анимация, это действительно прекрасно!

0
Kjuly

Я не знаю ни одного свойства UIScrollView, которое бы позволяло это. Было бы плохо для пользователя, чтобы иметь возможность отключить это, ИМХО.

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

0
Moshe