にUITextField
埋め込まれたUIScrollView
が最初の応答者になると (たとえば、ユーザーが文字を入力することによって)、 はUIScrollView
そのフィールドに自動的にスクロールします。それを無効にする方法はありますか?
11 に答える
Mosheの答えに基づいて...次のメソッドをサブクラスUIScrollView
化してオーバーライドします。
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
空のままにします。仕事は終わりました!
Swiftの場合:
class CustomScrollView: UIScrollView {
override func scrollRectToVisible(_ rect: CGRect, animated: Bool) { }
}
私は同じ問題に苦労してきましたが、ついに解決策を見つけました。
呼び出しトレースを追跡して自動スクロールがどのように行われるかを調査したところ[UIFieldEditor scrollSelectionToVisible]
、UITextField
. UIScrollView
このメソッドは、 の最も近い祖先の に作用するようUITextField
です。
したがって、 で を同じサイズのnewで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];
}
お役に立てれば!
Taketo が述べたように、 aUITextField
がファーストレスポンダーになると、そのタイプの最初の親ビューUIScrollView
(存在する場合) がスクロールされてUITextField
表示されます。最も簡単なハックは、各 UITextField を単純にラップすることですUIScrollView
(または、理想的には、それらすべてを単一のダミーでラップしますUIScrollView
)。これは Taketo のソリューションと非常によく似ていますが、私の意見では、パフォーマンスがわずかに向上し、コード (または Interface Builder のインターフェイス) がずっときれいになります。
ルークの答えに基づいて、彼のソリューションが自動スクロールを完全に無効にする問題を処理するために、次のように選択的に無効にすることができます。
// 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で完全に設定できますが、いつでも完全に制御して再度有効にすることができます(ただし、なぜそうしたいのかは私にはわかりません).
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 を返すことができます。
このようにして、通常の動作や物事の流れを損なうことはありません。独自の改善を加えて、同じチャネルで同じ機能を提供するだけです。
#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の答えを試しましたが、うまくいかないようです..私の場合は、スクロールビューがなく、いくつかのテキストフィールドを持つビューだけです。
そして最後に、私は回避策を得ました。必要なキーボードのデフォルトの通知名は 2 つあります。
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}}
が表示されたときのビューのフレームです。
ところで、ビューのフレーム変更は自動的にアニメーションに適用されます。これは本当に完璧です!
一番上にテキスト フィールドがあり、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];
}
}
それを可能にするプロパティを知りませんUIScrollView
。それを無効にできるのは、ユーザーエクスペリエンスが悪いでしょう、IMHO。
UIScrollView
とはいえ、メソッドの一部をサブクラス化およびオーバーライドして、UITextfield
スクロールする前に がファーストレスポンダーではないことを確認することは可能かもしれません。