当UITextField成为第一响应者时,禁用UIScrollView滚动

当UITextFieldembedded到UIScrollView成为第一响应者时,通过让用户input一些字符,UIScrollView自动滚动到该字段,有什么办法可以禁用?

通过https://bugreport.apple.com复制rdar:// 16538222

基于摩西的回答…

子类UIScrollView并重写以下方法:

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

把它留空。 任务完成!

我一直在努力解决同样的问题,最后我find了一个解决scheme。

我已经通过跟踪调用跟踪来调查自动滚动是如何完成的,并且发现在UITextField键入一个字母时会调用内部的[UIFieldEditor scrollSelectionToVisible] 。 此方法似乎作用于UITextField的最近祖先的UIScrollView

所以,在textFieldDidBeginEditing ,通过用与它相同大小的新UIScrollView包装UITextField (也就是将视图插入到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用于恢复默认的滚动行为,当用户自己启动滚动时。

正如Taketo提到的那样,当一个UITextField被作为第一响应者时,它的第一个父types的UIScrollView视图(如果存在的话)被滚动,使得UITextField可见。 最简单的方法是简单地将每个UITextField包装在一个UIScrollView中(或者理想的情况是将所有的UITextField包装在一个虚拟的UIScrollView中)。 这和Taketo的解决scheme非常相似,但是它应该会给你稍微更好的性能,并且会保持你的代码(或者你在Interface Builder中的接口)在我看来更清洁。

它看起来像包含UITextfield的UIScrollview,自动调整其内容偏移量; 当textfield将成为第一响应者。 这可以通过在第一个相同大小的滚动视图中添加文本字段,然后添加到主滚动视图来解决。 而不是直接添加到主滚动视图

  // 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返回自己的contentOffset。

这样你就不会损害事物的正常行为和stream动 – 只要在同一个通道中提供相同的function,就可以进行自己的改进。

 #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的答案,但似乎不行。我的情况是,我没有一个滚动视图,只是一个视图与几个文本字段。

最后,我有一个解决方法。 有两个我需要键盘的默认通知名称:

  • 当键盘确实显示时, 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}}是键盘显示时的视图框架。

顺便说一下,视图的框架将自动应用animation,这真是完美!

我不知道UIScrollView的任何属性会允许的。 恕我直言,这将是糟糕的用户体验,能够禁用。

也就是说,可以inheritanceUIScrollView并覆盖其一些方法来检查UITextfield在滚动之前不是第一响应者。

我有一个顶部的文本字段的集合视图,模仿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]; } } 

基于卢克的回答,为了解决他的解决scheme完全禁用自动滚动的问题,可以select性地禁用它,如下所示:

 // 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中完全设置它来禁用自动滚动,但随时可以完全控制重新启用它(尽pipe为什么你想超越我)。

一个更简单的方法来停止滚动视图滚动,当你select一个textField是在你的viewController :: viewWillAppear()不要调用[super viewWillAppear];

您可以随意控制滚动。