UITextField
に埋め込まれたUIScrollView
が最初のレスポンダーになると、ユーザーが何らかの文字を入力すると、UIScrollView
はそのフィールドに自動的にスクロールし、それを無効にしますか?
モシェの答えに基づいて...
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
の定義は、ユーザー自身がスクロールを開始したときに、デフォルトのスクロール動作を復元するために使用されます。
Taketoが述べたように、UITextField
がファーストレスポンダーになると、UIScrollView
型(存在する場合)の最初の親ビューがスクロールされて、そのUITextField
が表示されます。最も簡単なハックは、各UITextFieldをUIScrollView
にラップすることです(理想的には、それらすべてを単一のダミーUIScrollView
にラップすることです)。これはTaketoのソリューションと非常によく似ていますが、パフォーマンスがわずかに向上するはずで、私の意見ではコード(またはInterface Builderのインターフェイス)がずっときれいになります。
Lukeの答えに基づいて、彼のソリューションが自動スクロールを完全に無効にするという問題を処理するには、次のように選択的に無効にすることができます。
// 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のように見え、コンテンツオフセットを自動調整します。テキストフィールドがファーストレスポンダーになるとき。これは、最初に同じサイズのスクロールビューにテキストフィールドを追加してから、メインのスクロールビューに追加することで解決できます。メインスクロールビューに直接追加する代わりに
// 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
コレクションビューの一番上にテキストフィールドがあり、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];
}
}
@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}}
は、キーボードが表示されたときのビューのフレームです。
そして、b.t.w。、ビューのフレーム変更は自動的にアニメーションに適用されます、これは本当に完璧です!
それを許可するUIScrollView
のプロパティは知りません。私見では、それを無効にできるのはユーザーエクスペリエンスの低下でしょう。
ただし、スクロールする前に、UIScrollView
をサブクラス化し、そのメソッドの一部をオーバーライドして、UITextfield
がファーストレスポンダーではないことを確認することができます。