Ответ 1
Основываясь на ответе Моше...
Подкласс UIScrollView и переопределить следующий метод:
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
Оставьте его пустым. Задание выполнено!
Когда UITextField, встроенный в UIScrollView, становится первым ответчиком, например, если пользователь вводит какой-то символ, UIScrollView автоматически прокручивается до этого поля, есть ли способ отключить его?
Дубликат rdar://16538222 над https://bugreport.apple.com
Основываясь на ответе Моше...
Подкласс UIScrollView и переопределить следующий метод:
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
Оставьте его пустым. Задание выполнено!
Я боролся с той же проблемой, и наконец нашел решение.
Я исследовал, как выполняется автоматический прокрутка, отслеживая трассировку вызова, и обнаружил, что внутренний [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];
}
надеюсь, что это поможет!
У меня была та же проблема с отключением автоматической прокрутки 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
используется для восстановления поведения прокрутки по умолчанию, когда сам пользователь инициирует прокрутку.
Как упоминал Такето, когда UITextField создается первым ответчиком, его первое родительское представление типа UIScrollView (если оно существует) прокручивается, чтобы сделать видимым UITextField. Самый простой взлом - просто обернуть каждый UITextField в UIScrollView (или, в идеале, обернуть все их в один манекен UIScrollView). Это очень похоже на решение Taketo, но оно должно дать вам немного лучшую производительность, и я буду держать ваш код (или ваш интерфейс в Interface Builder) более чистым, на мой взгляд.
Похоже, UIScrollview, который содержит UITextfield, автоматически настраивает смещение содержимого; когда текстовое поле станет первым ответчиком. Это можно решить, добавив сначала текстовое поле в scrollview того же размера, а затем добавив его в основное представление прокрутки. вместо прямого добавления в основной scrollview
// 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
Так я это делаю:
Это очень просто, вы можете вернуть свой собственный контент для любого 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
Я пробовал ответить @TaketoSano, но, похоже, не работает. Мое дело в том, что у меня нет scrollview, просто просмотр с несколькими текстовыми полями.
И наконец, у меня есть обходное решение. Для клавиатуры требуются два имени по умолчанию:
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}}
- это рамка просмотра, когда клавиатура показывала.
И b.t.w., изменение кадра представления будет автоматически применено к анимации, это действительно идеально!
Основываясь на ответе Люка, чтобы решить проблему, что его решение полностью отключает автопрокрутку, вы можете отключить его выборочно следующим образом:
// 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
Таким образом, вы можете полностью настроить его в Interface Builder, чтобы отключить автопрокрутку, но в любой момент можно полностью включить его, чтобы снова включить его (хотя почему вы хотите, чтобы это было выше меня).
Я не знаю какого-либо свойства UIScrollView, которое позволит это. Было бы плохой пользовательский интерфейс, чтобы иметь возможность отключить это, ИМХО.
Тем не менее, возможно подкласс UIScrollView и переопределить некоторые из его методов, чтобы проверить, что поле UIText не является первым ответчиком перед прокруткой.
У меня есть представление коллекции с текстовым полем на самом верху, подражая 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];
}
}
Более простой способ остановить прокрутку прокрутки, когда вы выбираете textField, находится в вашем viewController:: viewWillAppear() НЕ вызывать [super viewWillAppear];
Затем вы можете управлять прокруткой по своему усмотрению.