IOS SDKの場合
キーボードを起動するUIView
を持つUITextField
があります。私はそれができるようにする必要があります。
キーボードが起動したら、UIScrollView
の内容をスクロールして他のテキストフィールドを見ることができるようにします
自動的に「ジャンプ」(上にスクロールする)または短縮
私はUIScrollView
が必要であることを知っています。 UIView
のクラスをUIScrollView
に変更しようとしましたが、それでもテキストボックスを上下にスクロールできません。
UIView
とUIScrollView
の両方が必要ですか?一方はもう一方の内側に入りますか?
アクティブなテキストフィールドに自動的にスクロールするためには、何を実装する必要がありますか?
理想的には、できる限りコンポーネントの設定をInterface Builderで行うようにします。それが必要なものだけのコードを書きたいのですが。
注:私が取り組んでいるUIView
(またはUIScrollView
)は、通常どおりに機能する必要があるタブバー(UITabBar
)によって表示されます。
編集:私はキーボードが立ち上がったときだけスクロールバーを追加しています。必要ではありませんが、たとえばユーザーがテキストボックスをスクロールしたり変更したりできるため、より優れたインターフェイスが提供されると思います。
キーボードが上下したときにUIScrollView
のフレームサイズを変更するところでうまくいきました。私は単に使っています:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
//Keyboard becomes visible
scrollView.frame = CGRectMake(scrollView.frame.Origin.x,
scrollView.frame.Origin.y,
scrollView.frame.size.width,
scrollView.frame.size.height - 215 + 50); //resize
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
//keyboard will hide
scrollView.frame = CGRectMake(scrollView.frame.Origin.x,
scrollView.frame.Origin.y,
scrollView.frame.size.width,
scrollView.frame.size.height + 215 - 50); //resize
}
しかし、これは自動的に "上に移動"したり、下のテキストフィールドを表示領域の中央に配置したりするものではありません。これは私が本当に望んでいることです。
ScrollView
name__はiPhoneの画面に収まらない場合にのみ必要です。(コンポーネントのスーパービューとしてScrollView
name__を追加する場合。キーボードが表示されたときにTextField
name__を上にスクロールするためだけに使用それからそれは必要ではないです。)
キーボードで隠されずにtextfields
name__を表示するための標準的な方法は、キーボードが表示されるたびにテキストフィールドを持つビューを上下に移動することです。
サンプルコードは次のとおりです。
#define kOFFSET_FOR_KEYBOARD 80.0
-(void)keyboardWillShow {
// Animate the current view out of the way
if (self.view.frame.Origin.y >= 0)
{
[self setViewMovedUp:YES];
}
else if (self.view.frame.Origin.y < 0)
{
[self setViewMovedUp:NO];
}
}
-(void)keyboardWillHide {
if (self.view.frame.Origin.y >= 0)
{
[self setViewMovedUp:YES];
}
else if (self.view.frame.Origin.y < 0)
{
[self setViewMovedUp:NO];
}
}
-(void)textFieldDidBeginEditing:(UITextField *)sender
{
if ([sender isEqual:mailTf])
{
//move the main view, so that the keyboard does not hide it.
if (self.view.frame.Origin.y >= 0)
{
[self setViewMovedUp:YES];
}
}
}
//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3]; // if you want to slide up the view
CGRect rect = self.view.frame;
if (movedUp)
{
// 1. move the view's Origin up so that the text field that will be hidden come above the keyboard
// 2. increase the size of the view so that the area behind the keyboard is covered up.
rect.Origin.y -= kOFFSET_FOR_KEYBOARD;
rect.size.height += kOFFSET_FOR_KEYBOARD;
}
else
{
// revert back to the normal state.
rect.Origin.y += kOFFSET_FOR_KEYBOARD;
rect.size.height -= kOFFSET_FOR_KEYBOARD;
}
self.view.frame = rect;
[UIView commitAnimations];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
また、複数のUIScrollView
で構成されているUITextFields
に多くの問題があり、そのうちの1つまたは複数は、編集中にキーボードによって隠されます。
UIScrollView
が適切にスクロールしない場合の考慮事項を次に示します。
1)contentSizeがUIScrollView
フレームサイズより大きいことを確認します。 UIScrollViews
を理解する方法は、UIScrollView
がcontentSizeで定義されたコンテンツの表示ウィンドウのようなものであることです。したがって、UIScrollview
をどこでもスクロールするには、contentSizeがUIScrollView
より大きくなければなりません。それ以外の場合、contentSizeで定義されたすべてがすでに表示されているため、スクロールは必要ありません。ところで、デフォルトのcontentSize = CGSizeZero
。
2)UIScrollView
は実際には「コンテンツ」へのウィンドウであることを理解したので、キーボードがUIScrollView's
を表示してウィンドウを覆い隠さないようにする方法は、UIScrollView
のサイズを変更して存在する場合、元のUIScrollView
frame.size.heightからキーボードの高さを引いたサイズのUIScrollView
ウィンドウがあります。これにより、ウィンドウはその小さな可視領域のみになります。
3)キャッチ:これを最初に実装したとき、編集したテキストフィールドのCGRect
を取得し、UIScrollView's
scrollRecToVisibleメソッドを呼び出す必要があると考えました。 UITextFieldDelegate
メソッドを呼び出してtextFieldDidBeginEditing
メソッドscrollRecToVisible
を実装しました。これは実際には、スクロールするとsnapUITextField
が所定の位置に配置されるという奇妙な副作用がありました。長い間、私はそれが何であるかを理解できませんでした。次に、textFieldDidBeginEditing
Delegateメソッドをコメントアウトしましたが、すべて機能します!!(???)。判明したように、UIScrollView
は実際に暗黙的に現在編集されているUITextField
を暗黙的に表示可能なウィンドウに持ってくると信じています。 UITextFieldDelegate
メソッドの実装とその後のscrollRecToVisible
の呼び出しは冗長であり、奇妙な副作用の原因でした。
キーボードが表示されたときにUITextField
のUIScrollView
を適切にスクロールする手順は次のとおりです。
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:self.view.window];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:self.view.window];
keyboardIsShown = NO;
//make contentSize bigger than your scrollSize (you will need to figure out for your own use case)
CGSize scrollContentSize = CGSizeMake(320, 345);
self.scrollView.contentSize = scrollContentSize;
}
- (void)keyboardWillHide:(NSNotification *)n
{
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// resize the scrollview
CGRect viewFrame = self.scrollView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.size.height += (keyboardSize.height - kTabBarHeight);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[self.scrollView setFrame:viewFrame];
[UIView commitAnimations];
keyboardIsShown = NO;
}
- (void)keyboardWillShow:(NSNotification *)n
{
// This is an ivar I'm using to ensure that we do not do the frame size adjustment on the `UIScrollView` if the keyboard is already shown. This can happen if the user, after fixing editing a `UITextField`, scrolls the resized `UIScrollView` to another `UITextField` and attempts to edit the next `UITextField`. If we were to resize the `UIScrollView` again, it would be disastrous. NOTE: The keyboard notification will fire even when the keyboard is already shown.
if (keyboardIsShown) {
return;
}
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// resize the noteView
CGRect viewFrame = self.scrollView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.size.height -= (keyboardSize.height - kTabBarHeight);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[self.scrollView setFrame:viewFrame];
[UIView commitAnimations];
keyboardIsShown = YES;
}
viewDidLoad
でキーボード通知に登録しますviewDidUnload
でキーボードの登録を解除しますcontentSize
がUIScrollView
でviewDidLoad
より大きく設定されていることを確認してくださいUIScrollView
UIScrollView
。UITextField
がタブ化されるたびにキーボード通知が送信されるため、キーボードが既に画面に表示されているかどうかを検出しますshrinking the UIScrollView
縮小注意すべきことの1つは、別のUIKeyboardWillShowNotification
をタブで移動すると、キーボードが既に画面上にある場合でもUITextField
が起動することです。キーボードが既に画面上にあるときに、UIScrollView
のサイズ変更を避けるために、ivarを使用してこれを処理しました。キーボードが既にあるときにUIScrollView
のサイズを誤って変更すると、悲惨な結果になります。
このコードがあなたの一部に多くの頭痛の種を救うことを願っています。
docs で提供されているように、実際にはちょうどAppleの実装を使うのが最善です。しかし、彼らが提供するコードは不完全です。 keyboardWasShown:
のコメントのすぐ下にある部分を次のように置き換えます。
NSDictionary* info = [aNotification userInfo];
CGRect keyPadFrame=[[UIApplication sharedApplication].keyWindow convertRect:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] fromView:self.view];
CGSize kbSize =keyPadFrame.size;
CGRect activeRect=[self.view convertRect:activeField.frame fromView:activeField.superview];
CGRect aRect = self.view.bounds;
aRect.size.height -= (kbSize.height);
CGPoint Origin = activeRect.Origin;
Origin.y -= backScrollView.contentOffset.y;
if (!CGRectContainsPoint(aRect, Origin)) {
CGPoint scrollPoint = CGPointMake(0.0,CGRectGetMaxY(activeRect)-(aRect.size.height));
[backScrollView setContentOffset:scrollPoint animated:YES];
}
Appleのコードの問題点は次のとおりです。(1)ポイントがビューのフレーム内にあるかどうかは常に計算されますが、これはScrollView
なのですでにスクロールされているため、オフセットを考慮する必要があります。
Origin.y -= scrollView.contentOffset.y
(2)これらはcontentOffsetをキーボードの高さだけシフトしますが、反対にします(contentOffset
を画面に表示される高さだけシフトします。
activeField.frame.Origin.y-(aRect.size.height)
textFieldDidBeginEditting
とtextFieldDidEndEditing
では、以下のように関数[self animateTextField:textField up:YES]
を呼び出します。
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField:textField up:YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField:textField up:NO];
}
-(void)animateTextField:(UITextField*)textField up:(BOOL)up
{
const int movementDistance = -130; // Tweak as needed
const float movementDuration = 0.3f; // Tweak as needed
int movement = (up ? movementDistance : -movementDistance);
[UIView beginAnimations: @"animateTextField" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
このコードがお役に立てば幸いです。
スウィフト2
func animateTextField(textField: UITextField, up: Bool)
{
let movementDistance:CGFloat = -130
let movementDuration: Double = 0.3
var movement:CGFloat = 0
if up
{
movement = movementDistance
}
else
{
movement = -movementDistance
}
UIView.beginAnimations("animateTextField", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
UIView.commitAnimations()
}
func textFieldDidBeginEditing(textField: UITextField)
{
self.animateTextField(textField, up:true)
}
func textFieldDidEndEditing(textField: UITextField)
{
self.animateTextField(textField, up:false)
}
スイフト3
func animateTextField(textField: UITextField, up: Bool)
{
let movementDistance:CGFloat = -130
let movementDuration: Double = 0.3
var movement:CGFloat = 0
if up
{
movement = movementDistance
}
else
{
movement = -movementDistance
}
UIView.beginAnimations("animateTextField", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
UIView.commitAnimations()
}
func textFieldDidBeginEditing(textField: UITextField)
{
self.animateTextField(textField: textField, up:true)
}
func textFieldDidEndEditing(textField: UITextField)
{
self.animateTextField(textField: textField, up:false)
}
TextFieldを使うだけで:
1a)Interface Builder
を使用する:すべてのTextFields => Edit => Embed In => ScrollViewを選択します。
1b)scrollViewという名前のUIScrollViewにTextFieldを手動で埋め込む
2)UITextFieldDelegate
を設定
3)各textField.delegate = self;
を設定する(またはInterface Builder
に接続する)
4) コピー/貼り付け:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
CGPoint scrollPoint = CGPointMake(0, textField.frame.Origin.y);
[scrollView setContentOffset:scrollPoint animated:YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
[scrollView setContentOffset:CGPointZero animated:YES];
}
ユニバーサルソリューション の場合、これは IQKeyboardManager を実装するための私のアプローチでした。
Step1: - シングルトンクラスにUITextField
、UITextView
、およびUIKeyboard
のグローバル通知を追加しました。 IQKeyboardManager と呼びます。
Step2: - UIKeyboardWillShowNotification
、UITextFieldTextDidBeginEditingNotification
、UITextViewTextDidBeginEditingNotification
の通知が見つかったら、UIWindow.rootViewController
階層からtopMostViewController
インスタンスを取得します。その上でUITextField
/UITextView
を正しく発見するためには、topMostViewController.view
のフレームを調整する必要があります。
Step3: - 最初に回答したUITextField
/UITextView
に対するtopMostViewController.view
の予想移動距離を計算しました。
Step4: - 予想される移動距離に合わせてtopMostViewController.view.frame
を上下に移動しました。
Step5: - UIKeyboardWillHideNotification
、UITextFieldTextDidEndEditingNotification
、またはUITextViewTextDidEndEditingNotification
の通知が見つかった場合は、UIWindow.rootViewController
階層からtopMostViewController
インスタンスを取得します。
Step6: - 元の位置に戻す必要があるtopMostViewController.view
の擾乱距離を計算しました。
Step7: - 距離に応じてtopMostViewController.view.frame
を元に戻しました。
Step8: - アプリロード時にシングルトンをインスタンス化します IQKeyboardManager classインスタンスなので、アプリ内のすべてのUITextField
/UITextView
は予想される移動距離に応じて自動的に調整されます。
これですべてです IQKeyboardManager /を使用して、 コード行を追加しない 本当に!関連するソースファイルをプロジェクトにドラッグアンドドロップするだけです。 IQKeyboardManager もサポートしています デバイスの向き 、 自動UIToolbar管理 、 KeybkeyboardDistanceFromTextField そして、あなたが思う以上のこと。
私は普遍的なドロップインUIScrollView
、UITableView
、さらにはUICollectionView
というサブクラスをまとめました。このサブクラス内のすべてのテキストフィールドをキーボードの邪魔にならないように移動します。
キーボードが表示されようとしているとき、サブクラスは編集しようとしているサブビューを見つけ、そのビューが表示されるようにフレームとコンテンツのオフセットを調整します。キーボードが消えると、以前のサイズに戻ります。
UITableView
ベースのインターフェース、または手動で配置されたビューで構成されるインターフェースのいずれかで、基本的にどのような設定でも機能するはずです。
ここがここにある: キーボードの邪魔にならないようにテキストフィールドを動かすための解決策
Swift /プログラマーの方へ:
これはあなたのためにすべてをするでしょう、単にあなたのView Controllerクラスにこれらを入れて、あなたのView ControllerにUITextFieldDelegate
を実装し、self
にtextFieldのデリゲートを設定
textField.delegate = self // Setting delegate of your UITextField to self
デリゲートコールバックメソッドを実装します。
func textFieldDidBeginEditing(textField: UITextField) {
animateViewMoving(true, moveValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
animateViewMoving(false, moveValue: 100)
}
// Lifting the view up
func animateViewMoving (up:Bool, moveValue :CGFloat){
let movementDuration:NSTimeInterval = 0.3
let movement:CGFloat = ( up ? -moveValue : moveValue)
UIView.beginAnimations( "animateView", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration )
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
UIView.commitAnimations()
}
すでに多くの答えがありますが、それでも「完璧な」バグのない、後方互換性のある、ちらつきのないアニメーションに必要なすべての派手なポジショニングのものが上記の解決策にはありません。 (フレーム/境界とcontentOffsetを一緒にアニメートするときのバグ、異なるインターフェイスの向き、iPadの分割キーボードなど)
私の解決策を教えてください。
(あなたがUIKeyboardWill(Show|Hide)Notification
を設定したと仮定します)
// Called when UIKeyboardWillShowNotification is sent
- (void)keyboardWillShow:(NSNotification*)notification
{
// if we have no view or are not visible in any window, we don't care
if (!self.isViewLoaded || !self.view.window) {
return;
}
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardFrameInWindow;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];
// the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view
CGRect keyboardFrameInView = [self.view convertRect:keyboardFrameInWindow fromView:nil];
CGRect scrollViewKeyboardIntersection = CGRectIntersection(_scrollView.frame, keyboardFrameInView);
UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);
// this is an old animation method, but the only one that retains compaitiblity between parameters (duration, curve) and the values contained in the userInfo-Dictionary.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
_scrollView.contentInset = newContentInsets;
_scrollView.scrollIndicatorInsets = newContentInsets;
/*
* Depending on visual layout, _focusedControl should either be the input field (UITextField,..) or another element
* that should be visible, e.g. a purchase button below an amount text field
* it makes sense to set _focusedControl in delegates like -textFieldShouldBeginEditing: if you have multiple input fields
*/
if (_focusedControl) {
CGRect controlFrameInScrollView = [_scrollView convertRect:_focusedControl.bounds fromView:_focusedControl]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview
controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, -10); // replace 10 with any Nice visual offset between control and keyboard or control and top of the scroll view.
CGFloat controlVisualOffsetToTopOfScrollview = controlFrameInScrollView.Origin.y - _scrollView.contentOffset.y;
CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;
// this is the visible part of the scroll view that is not hidden by the keyboard
CGFloat scrollViewVisibleHeight = _scrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;
if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question
// scroll up until the control is in place
CGPoint newContentOffset = _scrollView.contentOffset;
newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);
// make sure we don't set an impossible offset caused by the "Nice visual offset"
// if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies
newContentOffset.y = MIN(newContentOffset.y, _scrollView.contentSize.height - scrollViewVisibleHeight);
[_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
} else if (controlFrameInScrollView.Origin.y < _scrollView.contentOffset.y) {
// if the control is not fully visible, make it so (useful if the user taps on a partially visible input field
CGPoint newContentOffset = _scrollView.contentOffset;
newContentOffset.y = controlFrameInScrollView.Origin.y;
[_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
}
}
[UIView commitAnimations];
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillHide:(NSNotification*)notification
{
// if we have no view or are not visible in any window, we don't care
if (!self.isViewLoaded || !self.view.window) {
return;
}
NSDictionary *userInfo = notification.userInfo;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
// undo all that keyboardWillShow-magic
// the scroll view will adjust its contentOffset apropriately
_scrollView.contentInset = UIEdgeInsetsZero;
_scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
[UIView commitAnimations];
}
Shiun氏は、「結局のところ、UIScrollViewは暗黙的に現在編集中のUITextFieldを表示可能ウィンドウに暗黙的に表示する」と述べた。これはiOS 3.1.3には当てはまるが、3.2、4.0、または4.1には当てはまらない。 UITextFieldをiOS> = 3.2で表示するためには、明示的にscrollRectToVisibleを追加する必要がありました。
考慮すべきことの1つは、あなたがUITextField
を単独で使いたいかどうかです。 UITextFields
の外でUITableViewCells
を実際に使用している、うまく設計されたiPhoneアプリケーションに出会ったことはありません。
余分な作業になりますが、すべてのデータ入力ビューとテーブルビューを実装することをお勧めします。 UITextView
をUITableViewCells
に追加してください。
これ はこの問題の解決策を詳しく述べたものです。 「キーボードの下にあるコンテンツの移動」の下にあるソースコードを見てください。それはかなり簡単です。
編集:例には週の不調があることに気づいた。あなたはおそらくUIKeyboardWillHideNotification
の代わりにUIKeyboardDidHideNotification
を聴きたくなるでしょう。それ以外の場合は、キーボードを閉じるアニメーションの間、キーボードの後ろにあるスクロールビューが切り取られます。
最も簡単な解決策が見つかりました
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField: textField up: YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField: textField up: NO];
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
const int movementDistance = 80; // Tweak as needed
const float movementDuration = 0.3f; // Tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
多くのUITextFieldに有効な小さな修正
#pragma mark UIKeyboard handling
#define kMin 150
-(void)textFieldDidBeginEditing:(UITextField *)sender
{
if (currTextField) {
[currTextField release];
}
currTextField = [sender retain];
//move the main view, so that the keyboard does not hide it.
if (self.view.frame.Origin.y + currTextField.frame.Origin. y >= kMin) {
[self setViewMovedUp:YES];
}
}
//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3]; // if you want to slide up the view
CGRect rect = self.view.frame;
if (movedUp)
{
// 1. move the view's Origin up so that the text field that will be hidden come above the keyboard
// 2. increase the size of the view so that the area behind the keyboard is covered up.
rect.Origin.y = kMin - currTextField.frame.Origin.y ;
}
else
{
// revert back to the normal state.
rect.Origin.y = 0;
}
self.view.frame = rect;
[UIView commitAnimations];
}
- (void)keyboardWillShow:(NSNotification *)notif
{
//keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately
if ([currTextField isFirstResponder] && currTextField.frame.Origin.y + self.view.frame.Origin.y >= kMin)
{
[self setViewMovedUp:YES];
}
else if (![currTextField isFirstResponder] && currTextField.frame.Origin.y + self.view.frame.Origin.y < kMin)
{
[self setViewMovedUp:NO];
}
}
- (void)keyboardWillHide:(NSNotification *)notif
{
//keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately
if (self.view.frame.Origin.y < 0 ) {
[self setViewMovedUp:NO];
}
}
- (void)viewWillAppear:(BOOL)animated
{
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:self.view.window];
}
- (void)viewWillDisappear:(BOOL)animated
{
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
}
RPDPのコードは、テキストフィールドをキーボードの邪魔にならない場所に移動しました。しかし、キーボードを使用して却下した後に上部にスクロールすると、上部はビューの外側にスクロールアップされています。これはシミュレータとデバイスに当てはまります。そのビューの上部にあるコンテンツを読むには、ビューをリロードする必要があります。
彼の次のコードは、見解を元に戻すことになっていませんか?
else
{
// revert back to the normal state.
rect.Origin.y += kOFFSET_FOR_KEYBOARD;
rect.size.height -= kOFFSET_FOR_KEYBOARD;
}
UIScrollViewのサイズを変更して、ビューを上に移動することが正しいアプローチであるかどうかわかりません。 article について少し詳しく説明しました
元のビューステートに戻すには、以下を追加します。
-(void)textFieldDidEndEditing:(UITextField *)sender
{
//move the main view, so that the keyboard does not hide it.
if (self.view.frame.Origin.y < 0)
{
[self setViewMovedUp:NO];
}
}
非常に多くの解決策がありますが、私はそれがうまくいくまでに数時間を費やしました。それで、私はここにこのコードを入れました(ただプロジェクトに貼り付けてください、どんな修正も必要としません):
@interface RegistrationViewController : UIViewController <UITextFieldDelegate>{
UITextField* activeField;
UIScrollView *scrollView;
}
@end
- (void)viewDidLoad
{
[super viewDidLoad];
scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
//scrool view must be under main view - swap it
UIView* natView = self.view;
[self setView:scrollView];
[self.view addSubview:natView];
CGSize scrollViewContentSize = self.view.frame.size;
[scrollView setContentSize:scrollViewContentSize];
[self registerForKeyboardNotifications];
}
- (void)viewDidUnload {
activeField = nil;
scrollView = nil;
[self unregisterForKeyboardNotifications];
[super viewDidUnload];
}
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShown:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
-(void)unregisterForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)keyboardWillShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect frame = self.view.frame;
frame.size.height -= kbSize.height;
CGPoint fOrigin = activeField.frame.Origin;
fOrigin.y -= scrollView.contentOffset.y;
fOrigin.y += activeField.frame.size.height;
if (!CGRectContainsPoint(frame, fOrigin) ) {
CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.Origin.y + activeField.frame.size.height - frame.size.height);
[scrollView setContentOffset:scrollPoint animated:YES];
}
}
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
[scrollView setContentOffset:CGPointZero animated:YES];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeField = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
activeField = nil;
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
S:誰かがすぐに望みの効果を生み出すのを手助けするコードがあるといいのですが。 (Xcode 4.5)
@ user271753
元の表示に戻すには
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
[self setViewMovedUp:NO];
return YES;
}
この短いトリックを試してください。
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField: textField up: YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField: textField up: NO];
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
const int movementDistance = textField.frame.Origin.y / 2; // Tweak as needed
const float movementDuration = 0.3f; // Tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
ビューフレームを移動できるようにするには、スクロールビューは必要ありません。 viewcontroller's
ビューのフレームを変更して、ビュー全体がキーボードの上に最初の応答テキストフィールドを配置するのに十分なだけ上に移動するようにすることができます。この問題に遭遇したとき、これを行うUIViewController
のサブクラスを作成しました。キーボードが通知を表示し、ファーストレスポンダのサブビューを見つけ、(必要に応じて)メインビューを上方向にアニメートして、ファーストレスポンダがキーボードの上にくるようにします。キーボードが非表示になると、ビューは元の位置に戻ります。
このサブクラスを使用するには、カスタムView Controllerを GMKeyboardVC のサブクラスにして、この機能を継承します(viewWillAppear
とviewWillDisappear
を実装する場合は、必ずsuperを呼び出す必要があります)。クラスは github です。
Swift 4。
簡単に上下に移動できますUITextField
またはUIView
With UIKeyBoard
With Animation
-
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var textField: UITextField!
@IBOutlet var chatView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
textField.resignFirstResponder()
}
@objc func keyboardWillChange(notification: NSNotification) {
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let deltaY = targetFrame.Origin.y - curFrame.Origin.y
print("deltaY",deltaY)
UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.chatView.frame.Origin.y+=deltaY // Here You Can Change UIView To UITextField
},completion: nil)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
これは私が特定のレイアウトのために思いついたハックの解決策です。このソリューションは、セクションをスクロールして表示するという点でMatt Gallagherソリューションと似ています。私はまだiPhoneの開発に慣れていないので、レイアウトがどのように機能するのかについて慣れていません。したがって、このハック。
私の実装では、フィールド内をクリックするときのスクロールと、ユーザーがキーボードで次に選択するときのスクロールをサポートする必要がありました。
私は775の高さのUIViewを持っていました。コントロールは広いスペースの上に3のグループに基本的に広げられます。私は次のようなIBレイアウトになった。
UIView -> UIScrollView -> [UI Components]
これがハックです
UIScrollViewの高さを実際のレイアウト(1250)より500単位大きく設定しました。次に、スクロールする必要がある絶対位置と、IBタグ番号に基づいてそれらを取得するための単純な関数を含む配列を作成しました。
static NSInteger stepRange[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410
};
NSInteger getScrollPos(NSInteger i) {
if (i < TXT_FIELD_INDEX_MIN || i > TXT_FIELD_INDEX_MAX) {
return 0 ;
return stepRange[i] ;
}
TextFieldDidBeginEditingとtextFieldShouldReturnに次の2行のコードを使用するだけです(次のフィールドナビゲーションを作成する場合は後者)。
CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;
例。
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
NSInteger nextTag = textField.tag + 1;
UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
if (nextResponder) {
[nextResponder becomeFirstResponder];
CGPoint point = CGPointMake(0, getScrollPos(nextTag)) ;
[self.scrollView setContentOffset:point animated:YES] ;
}
else{
[textField resignFirstResponder];
}
return YES ;
}
このメソッドは、他のメソッドのように 'スクロールバック'しません。これは必要条件ではありませんでした。これもかなり「背の高い」UIViewのためのもので、私は内部レイアウトエンジンを学ぶ日がありませんでした。
ここで私はキーパッドを扱うための最も簡単な解決策を見つけました。
サンプルコードの下にコピーアンドペーストして、テキストフィールドまたは上に移動したいビューを変更するだけです。
ステップ1
あなたのコントローラーの2つの方法の下でちょうどコピーアンドペースト
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
- (void)deregisterFromKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
ステップ2
キーパッド通知をそれぞれviewWillAppearおよび viewWillDisappearメソッドに登録し、登録解除します。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self registerForKeyboardNotifications];
}
- (void)viewWillDisappear:(BOOL)animated
{
[self deregisterFromKeyboardNotifications];
[super viewWillDisappear:animated];
}
ステップ-3
ここで魂の部分が来る、ちょうどあなたのテキストフィールドを交換して、あなたがどのくらい上方に動かしたいかの高さを変える。
- (void)keyboardWasShown:(NSNotification *)notification
{
NSDictionary* info = [notification userInfo];
CGSize currentKeyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
//you need replace your textfield instance here
CGPoint textFieldOrigin = self.tokenForPlaceField.frame.Origin;
CGFloat textFieldHeight = self.tokenForPlaceField.frame.size.height;
CGRect visibleRect = self.view.frame;
visibleRect.size.height -= currentKeyboardSize.height;
if (!CGRectContainsPoint(visibleRect, textFieldOrigin))
{
//you can add yor desired height how much you want move keypad up, by replacing "textFieldHeight" below
CGPoint scrollPoint = CGPointMake(0.0, textFieldOrigin.y - visibleRect.size.height + textFieldHeight); //replace textFieldHeight to currentKeyboardSize.height, if you want to move up with more height
[self.scrollView setContentOffset:scrollPoint animated:YES];
}
}
- (void)keyboardWillBeHidden:(NSNotification *)notification
{
[self.scrollView setContentOffset:CGPointZero animated:YES];
}
Reference:さて、 この男に感謝します 、この美しいコードスニップを共有した、きれいな解決策.
これが誰かにとって非常に有用なものになることを願っています。
主題に関する初心者のための良いチュートリアルを探していて、最高のチュートリアル ここ を見つけました。
チュートリアルの下部にあるMIScrollView.h
の例では、必ずスペースを
@property (nonatomic, retain) id backgroundTapDelegate;
お分かりのように.
UITextField
がUITableViewCell
内にある場合は、スクロールは自動的に設定されます。
そうでない場合は、おそらくテーブルビューの不適切なコード/設定が原因です。
例えば、以下のように一番下に1つのUITextField
を付けて私の長いテーブルをリロードすると、
-(void) viewWillAppear:(BOOL)animated
{
[self.tableview reloadData];
}
それから下部の私のテキストフィールドは、私がテキストフィールドの内側をクリックしたときに現れたキーボードによって隠されていました。
これを直すために私はこれをしなければならなかった -
-(void) viewWillAppear:(BOOL)animated
{
//add the following line to fix issue
[super viewWillAppear:animated];
[self.tableview reloadData];
}
あなたが一行も書く必要がないこの第三者を使う
https://github.com/hackiftekhar/IQKeyboardManager
プロジェクトをダウンロードし、プロジェクトにIQKeyboardManagerをドラッグアンドドロップします。問題がある場合は、README文書を参照してください。
みんな本当にキーボードを管理するためにその頭痛を取り除きます..
ありがとう、そして頑張ってください!
注 :この答えはあなたのtextFieldがscrollViewにあると仮定しています。
私は自分のビューのフレームを台無しにするのではなく、scrollContentInsetとscrollContentOffsetを使用してこれを処理することを好みます。
最初にキーボード通知を聞きましょう
//call this from viewWillAppear
-(void)addKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
//call this from viewWillDisappear
-(void)removeKeyboardNotifications{
[[NSNotificationCenter default
Center] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
次のステップは、現在の最初のレスポンダを表すプロパティを保持することです(現在UITextfield/UITextVIewにはキーボードがあります)。
このプロパティを設定するためにデリゲートメソッドを使います。他のコンポーネントを使用している場合は、似たようなものが必要になります。
Textfieldの場合はdidBeginEditingに、textViewの場合はshouldBeginEditingに設定します。これは、textViewDidBeginEditingが何らかの理由でUIKeyboardWillShowNotificationの後に呼び出されるためです。
-(BOOL)textViewShouldBeginEditing:(UITextView * )textView{
self.currentFirstResponder = textView;
return YES;
}
-(void)textFieldDidBeginEditing:(UITextField *)textField{
self.currentFirstResponder = textField;
}
最後に、これが魔法です
- (void)keyboardWillShow:(NSNotification*)aNotification{
NSDictionary* info = [aNotification userInfo];
CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
/*if currentFirstResponder is overlayed by the keyboard, move it so it bottom ends where the keyboard begins*/
if(self.currentFirstResponder){
//keyboard Origin in currentFirstResponderFrame
CGPoint keyboardOrigin = [self.currentFirstResponder convertPoint:kbFrame.Origin fromView:nil];
float spaceBetweenFirstResponderAndKeyboard = abs(self.currentFirstResponder.frame.size.height-keyboardOrigin.y);
//only scroll the scrollview if keyboard overlays the first responder
if(spaceBetweenFirstResponderAndKeyboard>0){
//if i call setContentOffset:animate:YES it behaves differently, not sure why
[UIView animateWithDuration:0.25 animations:^{
[self.scrollView setContentOffset:CGPointMake(0,self.scrollView.contentOffset.y+spaceBetweenFirstResponderAndKeyboard)];
}];
}
}
//set bottom inset to the keyboard height so you can still scroll the whole content
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbFrame.size.height, 0.0);
_scrollView.contentInset = contentInsets;
_scrollView.scrollIndicatorInsets = contentInsets;
}
- (void)keyboardWillHide:(NSNotification*)aNotification{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
_scrollView.contentInset = contentInsets;
_scrollView.scrollIndicatorInsets = contentInsets;
}
これはSwiftを使った解決策です。
import UIKit
class ExampleViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var textField1: UITextField!
@IBOutlet var textField2: UITextField!
@IBOutlet var textField3: UITextField!
@IBOutlet var textField4: UITextField!
@IBOutlet var textField5: UITextField!
var activeTextField: UITextField!
// MARK: - View
override func viewDidLoad() {
super.viewDidLoad()
self.textField1.delegate = self
self.textField2.delegate = self
self.textField3.delegate = self
self.textField4.delegate = self
self.textField5.delegate = self
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.registerForKeyboardNotifications()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.unregisterFromKeyboardNotifications()
}
// MARK: - Keyboard
// Call this method somewhere in your view controller setup code.
func registerForKeyboardNotifications() {
let center: NSNotificationCenter = NSNotificationCenter.defaultCenter()
center.addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)
center.addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
}
func unregisterFromKeyboardNotifications () {
let center: NSNotificationCenter = NSNotificationCenter.defaultCenter()
center.removeObserver(self, name: UIKeyboardDidShowNotification, object: nil)
center.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
// Called when the UIKeyboardDidShowNotification is sent.
func keyboardWasShown (notification: NSNotification) {
let info : NSDictionary = notification.userInfo!
let kbSize = (info.objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue() as CGRect!).size
let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
// If active text field is hidden by keyboard, scroll it so it's visible
// Your app might not need or want this behavior.
var aRect = self.view.frame
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, self.activeTextField.frame.Origin) ) {
self.scrollView.scrollRectToVisible(self.activeTextField.frame, animated: true)
}
}
// Called when the UIKeyboardWillHideNotification is sent
func keyboardWillBeHidden (notification: NSNotification) {
let contentInsets = UIEdgeInsetsZero;
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
// MARK: - Text Field
func textFieldDidBeginEditing(textField: UITextField) {
self.activeTextField = textField
}
func textFieldDidEndEditing(textField: UITextField) {
self.activeTextField = nil
}
}
あなたは特定のフレームサイズでプログラム的にスクロールビューを追加する必要があります。 UIScrollViewDelegateを.hファイルに追加する必要があります。 viewDidLoad()で以下のように書く必要があるため、scrollviewを有効にする必要があります。
scrollview.scrollEnabled=YES;
scrollview.delegate=self;
scrollview.frame = CGRectMake(x,y,width,height);
//---set the content size of the scroll view---
[scrollview setContentSize:CGSizeMake(height,width)];
このようにして、あなたはあなたのx、y、幅と高さの値を追加することができます。
これを試して:
-(void)textFieldDidBeginEditing:(UITextField *)sender
{
if ([sender isEqual:self.m_Sp_Contact])
{
[self.m_Scroller setContentOffset:CGPointMake(0, 105)animated:YES];
}
}
Swift 2.0:
UIScrollViewを追加し、その上にtextFieldsを追加します。ストーリーボードからVCへの参照を作成します。
@IBOutlet weak var username: UITextField!
@IBOutlet weak var password: UITextField!
@IBOutlet weak var scrollView: UIScrollView!
これらのメソッドを追加します:UITextFieldDelegateおよびUIScrollViewDelegate。
//MARK:- TEXTFIELD METHODS
func textFieldShouldReturn(textField: UITextField) -> Bool {
if(username.returnKeyType == UIReturnKeyType.Default) {
password.becomeFirstResponder()
}
textField.resignFirstResponder()
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
dispatch_async(dispatch_get_main_queue()) {
let scrollPoint:CGPoint = CGPointMake(0,textField.frame.Origin.y/4)
self.scrollView!.setContentOffset(scrollPoint, animated: true);
}
}
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
dispatch_async(dispatch_get_main_queue()) {
UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) })
}
return true
}
override func touchesBegan(touches: Set<UITouch>,
withEvent event: UIEvent?) {
self.view.endEditing(true)
}
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
self.scrollView.scrollEnabled = true
dispatch_async(dispatch_get_main_queue()) {
UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true)
})
}
}
これはキーボード操作のための無料のライブラリです iPhoneアプリケーションのキーボード操作 。 1行のコードを書く必要があります。
[AutoScroller addAutoScrollTo:scrollView];
これは、フォームでキーボードを扱うのに最適です。
Swiftを使用している場合は、最善の方法はプロトコル指向プログラミングを使用することです。
まず最初にKeyboardCapable
プロトコルを作成しなければなりません。それはそれに適合するすべてのUIViewControllerにキーボードオブザーバを登録および登録解除する能力を与えます:
import Foundation
import UIKit
protocol KeyboardCapable: KeyboardAnimatable {
func keyboardWillShow(notification: NSNotification)
func keyboardWillHide(notification: NSNotification)
}
extension KeyboardCapable where Self: UIViewController {
func registerKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil)
}
func unregisterKeyboardNotifications() {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
}
上記のコードに無関係なKeyboardAnimatable
キーワードがあります。それは私たちが作成する必要がある次のプロトコルの名前です。
import Foundation
import UIKit
protocol KeyboardAnimatable {
}
extension KeyboardAnimatable where Self: UIViewController {
func performKeyboardShowFullViewAnimation(withKeyboardHeight height: CGFloat, andDuration duration: NSTimeInterval) {
UIView.animateWithDuration(duration, animations: { () -> Void in
self.view.frame = CGRectMake(view.frame.Origin.x, -height, view.bounds.width, view.bounds.height)
}, completion: nil)
}
func performKeyboardHideFullViewAnimation(withDuration duration: NSTimeInterval) {
UIView.animateWithDuration(duration, animations: { () -> Void in
self.view.frame = CGRectMake(view.frame.Origin.x, 0.0, view.bounds.width, view.bounds.height)
}, completion: nil)
}
}
このKeyboardAnimatable
プロトコルは、それに準拠するすべてのUIViewControllerに、それぞれビュー全体を上下にアニメーション化する2つのメソッドを与えます。
KeyboardCapable
がKeyboardAnimatable
に準拠していれば、すべてのUIViewControllerがKeyboardCapable
に準拠していて、KeyboardAnimatable
にも準拠しています。カッコいい。
UIViewController
がKeyboardCapable
に準拠し、キーボードイベントに反応するのを見てみましょう:
import Foundation
import UIKit
class TransferConfirmViewController: UIViewController, KeyboardCapable {
//MARK: - LIFE CYCLE
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
registerKeyboardNotifications()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
unregisterKeyboardNotifications()
}
//MARK: - NOTIFICATIONS
//MARK: Keyboard
func keyboardWillShow(notification: NSNotification) {
let keyboardHeight = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
performKeyboardShowFullViewAnimation(withKeyboardHeight: keyboardHeight, andDuration: animationDuration)
}
func keyboardWillHide(notification: NSNotification) {
let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
performKeyboardHideFullViewAnimation(withDuration: animationDuration)
}
}
これであなたのUIViewController
はキーボードイベントに反応し、結果としてアニメーション化します。
注:ビューをプッシュまたはプルする代わりにカスタムアニメーションが必要な場合は、KeyboardAnimatable
プロトコルでカスタムメソッドを定義するか、KeyboardCapable
関数でそれらを実行する必要があります。それはあなた次第です。
もっとずっと洗練された解決策はUIView
サブクラスを使って(これは必ずしも適切ではありませんが)親のフレーム変更時にすべてのサブビューを再計算することです(そして賢いこと:新しいフレームサイズが変わったら再計算するだけです、 CGRectEqualToRect
をオーバーライドして[super setFrame:frame_]
を呼び出す前に新しいフレームを比較するためのsetFrame
。これに対する唯一のキャッチは、あなたが使用しようとしているUIViewController
がおそらくキーボードイベントをリスンすべきであるということです(あるいは、便利なカプセル化のためにUIView
それ自身の中でそれをすることができます)。しかしUIKeyboardWillShowNotification
とUIKeyboardWillHideNotification
だけです。これはまさに滑らかに見えるようにするためです(CGがそれを呼び出すのを待っているなら、あなたはぎっしりの瞬間を得るでしょう)。
とにかく、これには正しいことをするUIView
サブクラスを構築するという利点があります。
単純な実装はdrawRect:
(don't)をオーバーライドすることでしょう、より良いのは単にlayoutSubviews
を使用することです(そしてそれからUIViewController
の中で、またはshowまたはshowのために呼び出されるSINGLEメソッドで[view setNeedsLayout
]を呼び出すことができません。隠す)。
この解決法はキーボードのオフセットのハードコーディング(分割されていない場合などに変更されます)を避けることができ、またあなたのビューが他の多くのビューのサブビューであり、それでも正しく反応することを意味します。
他に解決策がない限り、そのようなものをハードコーディングしないでください。あなたが正しいことをしていれば、OSはあなたに(あなたの新しいframe
サイズに基づいて)知的に再描画する必要があるだけの十分な情報を提供します。これはずっときれいで、あなたのやり方です すべき 物事をやる。 (ただし、もっと良い方法があるかもしれません。)
乾杯。
次のコードをクラスに入れて、必要に応じてカスタマイズするだけです。
-(void)textFieldDidBeginEditing:(UITextField *)textField {
//Show Keyboard
self.view.frame = CGRectMake(self.view.frame.Origin.x,
self.view.frame.Origin.y-50,
self.view.frame.size.width,
self.view.frame.size.height);
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
// Hide keyboard
self.view.frame = CGRectMake(self.view.frame.Origin.x,
self.view.frame.Origin.y+50,
self.view.frame.size.width,
self.view.frame.size.height);
}
Textfieldデリゲートメソッドを使ってもできます。以下のコードを確認してください。スクロールビューにテキストフィールドを配置したときに私には役に立ちます。
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if(textField == answer)
{
CGPoint cPoint = textField.frame.Origin;
[scrollView setContentOffset:CGPointMake(0, cPoint.y - 100) animated:YES];
}
}
注: あなたはあなたの見解に従ってcPoint.y - 100の値を変更する必要があります。
これが私のautolayoutを使ったバージョンです。
これは、テキストフィールド/テキストビューを含むビューをUIScrollViewに埋め込んで、下からスーパービューへの制約を設定し、アウトレットを作成し、通知を使用してキーボードの高さに応じて定数を更新することです。 Appleの例 here 、およびAutoLayoutを使用したUIScrollViewに関するAppleテクニカルノート here 。
1)ビューVをUIScrollView Sに埋め込む:すでに定数とサブビューを設定している場合は、ビューとサブビューをViewControllerのビューにコピー/貼り付けしてから、[エディタ] - > [埋め込み]メニューを使用しますコピーしたビューを最後に削除します。
2)以下の制約を設定してください。
スーパービューに続くS:0
スーパービューへのVトップスペース:0
スーパービューへのV先導スペース:0
Sと同じ幅のV
スーパービューへの最新の下Vサブビュー:20
3)最新の制約からView Controllerへのアウトレットを作成します
4)以下のコードを使用してください。
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomSpaceToContentView;
// ...
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// ...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Handle keyboard
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
self.bottomSpaceToContentView.constant = kBottomMargin + kbSize.height;
[self.view layoutIfNeeded];
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
self.bottomSpaceToContentView.constant = kBottomMargin;
[self.view layoutIfNeeded];
}
そしてtadaaaaa、それは機能します!
アプローチを伝えるために利用可能な多くの答えがあります。私は同じアプローチを取りましたが、実装は良くありません。
これが 基本のアイデア です。 keyboardWasShownメソッドを修正しました。
{
// Obtain keyboard Info
NSDictionary* info = [notification userInfo];
CGRect keyboardRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
keyboardRect = [self.view convertRect:keyboardRect fromView:nil];
// Obtain ScrollView Info w.r.t. top View
CGRect scrollViewRect = [self.view convertRect:self.scrollView.frame fromView:nil];
// Depending upon your screen Ui, Scroll View's bottom Edge might be at some offset from screen's bottom
// Calculate the exact offset
int scrollViewBottomOffset = self.view.frame.size.height - (scrollViewRect.Origin.y + scrollViewRect.size.height);
int heightToBeAdjusted = keyboardRect.size.height - scrollViewBottomOffset;
// We may also need to consider the Insets if already present with ScrollView. Let's keep it simple for now
// But we should store these, so that we can restore the Insets when Keyboard is gone
// origInsets = self.scrollView.contentInset;
// Set the new Insets for ScrollView
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, heightToBeAdjusted, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
// Visible frame (not overlapped by Keyboard)
CGRect visibleFrame = self.view.frame;
visibleFrame.size.height -= keyboardRect.size.height;
// Get the Rect for Textfield w.r.t self.view
CGRect activeFieldFrame = self.activeField.frame;
activeFieldFrame = [self.view convertRect:activeFieldFrame fromView:self.scrollView];
// Check if the TextField is Visible or not
if (!CGRectContainsRect(visibleFrame, activeFieldFrame) ) {
// Scroll to make it visible but for scrolling use the activeField frame w.r.t. to scroll View
[self.scrollView scrollRectToVisible:self.activeField.frame animated:YES];
}
}
そしてこのメソッドを追加してactiveFieldを初期化します。
- (IBAction)textFieldDidBeginEditing:(UITextField *)sender
{
self.activeField = sender;
}
これはデバイスから独立したオフセット計算です。キーボードとテキストフィールドの重なりの高さを取得します。
func keyboardShown(notification: NSNotification) {
let info = notification.userInfo!
let value: AnyObject = info[UIKeyboardFrameEndUserInfoKey]!
let rawFrame = value.CGRectValue
let keyboardFrame = view.convertRect(rawFrame, fromView: nil)
let screenHeight = UIScreen.mainScreen().bounds.size.height;
let Ylimit = screenHeight - keyboardFrame.size.height
let textboxOriginInSuperview:CGPoint = self.view.convertPoint(CGPointZero, fromCoordinateSpace: lastTextField!)
self.keyboardHeight = (textboxOriginInSuperview.y+self.lastTextField!.frame.size.height) - Ylimit
if(self.keyboardHeight>0){
self.animateViewMoving(true, moveValue: keyboardHeight!)
}else{
keyboardHeight=0
}
}
keyBoardHeightはオフセットです。
https://github.com/michaeltyson/TPKeyboardAvoiding このファイルをダウンロードしてテーブルビューにカスタムクラスを追加すると、すべてのことを管理できます。それはあなたが他のためにそれをチェックアウトすることができます多くのオプションがあります、これはあなたがキーボードを避けるために必要なすべてです
これは私が作ったUITextfield(および他の同様のフィールド)カテゴリです。これはtextfieldがキーボードを避けるようにするでしょう、あなたはこれをあなたのView Controllerにそのまま落とすことができなければなりません、そしてそれは動作するはずです。現在のテキストフィールドがアニメーションのあるキーボードの上にあるように画面全体を上に移動します
#import "UIView+avoidKeyboard.h"
#import "AppDelegate.h"
@implementation UIView (avoidKeyboard)
- (void) becomeFirstResponder {
if(self.isFirstResponder)
return;
[super becomeFirstResponder];
if ([self isKindOfClass:[UISearchBar class]] ||
[self isKindOfClass:[UITextField class]] ||
[self isKindOfClass:[UITextView class]])
{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
CGRect screenBounds = appDelegate.window.frame;
CGFloat keyboardHeight;
CGFloat keyboardY;
CGFloat viewsLowestY;
CGPoint Origin = [self.superview convertPoint:self.frame.Origin toView:appDelegate.window]; //get this views Origin in terms of the main screens bounds
if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){ //the window.frame doesnt take its orientation into account so if its sideways we must use the x value of the Origin instead of the y
keyboardHeight = 216;
keyboardY = screenBounds.size.height - keyboardHeight; //find the keyboards y coord relative to how much the main window has moved up
viewsLowestY = Origin.y + self.frame.size.height; //find the lowest point of this view
}
else {
keyboardHeight = 162;
keyboardY = screenBounds.size.width - keyboardHeight;
viewsLowestY = Origin.x + self.frame.size.height;
}
CGFloat difference = viewsLowestY - keyboardY + 20; //find if this view overlaps with the keyboard with some padding
if (difference > 0){ //move screen up if there is an overlap
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
CGRect frame = appDelegate.window.frame;
if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){
frame.Origin.y -= difference;
}
else {
frame.Origin.x -= difference;
}
appDelegate.window.frame = frame;
}
completion:nil];
}
}
}
//look at appDelegate to see when the keyboard is hidden
@end
あなたのappDelegateでこの関数を追加してください
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardHides:) name:UIKeyboardWillHideNotification object:nil]; //add in didFinishLaunchingWithOptions
...
- (void)keyboardHides:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
[window setFrame: CGRectMake(0, 0, window.frame.size.width, window.frame.size.height)];
} completion:nil];
}
次の手順に従ってください。
1).hファイルに次の変数を宣言します。
{
CGFloat animatedDistance;
}
2).mファイルに次の定数を宣言します。
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;
3)UITextFieldデリゲートを使用してキーボードを上下に移動します。
-(void) textFieldDidBeginEditing:(UITextField *)textField
{
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textFieldRect.Origin.y + 0.5 * textFieldRect.size.height;
CGFloat numerator =
midline - viewRect.Origin.y
- MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator =
(MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
* viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
{
heightFraction = 0.0;
}
else if (heightFraction > 1.0)
{
heightFraction = 1.0;
}
UIInterfaceOrientation orientation =
[[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait)
{
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
}
else
{
animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
}
CGRect viewFrame = self.view.frame;
viewFrame.Origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
}
-(void) textFieldDidEndEditing:(UITextField *)textField
{
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
{
CGRect viewFrame = self.view.frame;
viewFrame.Origin.y += animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
}
私はすべてを1つのクラスに包みます。あなたのviewcontrollerがロードされたときにこれらのコード行を呼び出すだけです:
- (void)viewDidLoad {
[super viewDidLoad];
KeyboardInsetScrollView *injectView = [[KeyboardInsetScrollView alloc] init];
[injectView injectToView:self.view withRootView:self.view];
}
これがサンプルプロジェクトのリンクです。
https://github.com/caohuuloc/KeyboardInsetScrollView
私は最近、メッセージングアプリで作業しているときにも同じような状況に陥っていました。私はキーボードの上にこだわるカスタムUIViewを作成し、あなたが自動的に必要なことのほとんどをする
http://www.thegameengine.org/wp-content/uploads/2013/11/message_composer_quad_1.jpg
このプロジェクトの背後にあるアイデアは、iMessageコンポジションビューAKAと同様に機能するものを作成することでした。
UIScrollViewのサイズを変更したり再設定したりするには、次のオプションのデリゲートメソッドを使用します。
- (void)messageComposerFrameDidChange:(CGRect)frame withAnimationDuration:(float)duration;
フレームが変更された(サイズ変更、位置変更、回転)たびに呼び出され、アニメーションの長さも提供します。この情報を使用して、必要に応じてUIScrollViewのフレームとコンテンツのインセットのサイズを変更できます。
これをポッドファイルに追加してください - > pod 'IQKeyboardManager'
それは、キーボード、スクロールビュー、その他すべてを処理することです。
あなたは何かをコーディングする必要はありません、より良い解決策を見つけることができませんでした!
テキストフィールドの表示、画面移動、複数のテキストフィールドがある場合は前後の矢印を処理する拡張機能があります。
また、削除できるカスタムの[完了]ボタンもあります。
これが最善の解決策であることがわかりました。下記のコードに従ってください。
以下をVertical Space - Bottom Layout Guide - TextField
制約に付けてください。
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomConst;
次に、キーボード通知用のオブザーバを追加します。
- (void)observeKeyboard {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
これをviewDidLoad
に追加してください
[self observeKeyboard];
最後にキーボードの変更を処理するメソッド。
- (void)keyboardWillShow:(NSNotification *)notification {
//THIS WILL MAKE SURE KEYBOARD DOESNT JUMP WHEN OPENING QUICKTYPE/EMOJI OR OTHER KEYBOARDS.
kbHeight = 0;
height = 0;
self.textViewBottomConst.constant = height;
self.btnViewBottomConst.constant = height;
NSDictionary *info = [notification userInfo];
NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardFrame = [kbFrame CGRectValue];
CGRect finalKeyboardFrame = [self.view convertRect:keyboardFrame fromView:self.view.window];
int kbHeight = finalKeyboardFrame.size.height;
int height = kbHeight + self.textViewBottomConst.constant;
self.textViewBottomConst.constant = height;
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
- (void)keyboardWillHide:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
self.textViewBottomConst.constant = 10;
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
Appleのように、はるかにシンプルでありながら一般化された方法では、キーパッドの高さを考慮します。これは、キーボードの上にカスタムツールバーを使用する場合に非常に役立ちます。 Appleのアプローチ こちら にはほとんど問題がありません。
これが私のアプローチです(Appleのやり方を少し変更しました)-
// UIKeyboardDidShowNotification
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
}
// UIKeyboardWillHideNotification
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
}
私はこれが遅すぎることを知っています、しかし私はそれをする私のやり方、特に将来の訪問者と共有したいと思いました。多くの良い方法が共有されていましたが、私はUIが完全に悪くなるのが好きではありませんでした。二つの部分を含む簡単な方法があります: -
CGAffineTransform(TranslationX: x, TranslationY: y)
を使用してください。 UIViewControllerを拡張する簡単なソリューション
簡単な解決策と最新のアニメーションAPI。 Origin.yを215に変更すると、どちらの値でもうまくいくようにカスタマイズできます。
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if (self.view.frame.Origin.y >= 0) {
[UIView animateWithDuration:0.5 animations:^{
self.view.frame = CGRectMake(self.view.frame.Origin.x, self.view.frame.Origin.y-215, self.view.frame.size.width, self.view.frame.size.height);
}];
}
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
if (self.view.frame.Origin.y < 0) {
[UIView animateWithDuration:0.5 animations:^{
self.view.frame = CGRectMake(self.view.frame.Origin.x, self.view.frame.Origin.y+215, self.view.frame.size.width, self.view.frame.size.height);
}];
}
}
@sumanthkodiの答えを広げたいと思います。
一部の人々が述べているように、 constraint を使用しているとUIViewは動きませんので、彼のアプローチは新しい実装では機能しません。
私は次のようにコードを編集し(そしてSwift 2.0に移植し)、それが何人かの人々に役立つことを願っています:
1)上に移動したいビューの垂直方向の拘束を参照します。
@IBOutlet var viewConstraint: NSLayoutConstraint!
ストーリーボードのこのvarを必ず制約付きで参照してください。
2)デリゲートを追加してリスナーを実装します。これは以前と同じ実装です。
class YourViewController: UIViewController, UITextFieldDelegate {
...
func textFieldDidBeginEditing(textField: UITextField) {
animateTextField(textField, up: true)
}
func textFieldDidEndEditing(textField: UITextField) {
animateTextField(textField, up: false)
}
...
}
3)アニメーションメソッドanimateTextField
をYourViewController
クラスに追加します。必要に応じて一時制約値を設定してください。
func animateTextField(textfield: UITextField, up: Bool) {
let originalConstraint = 50
let temporaryConstraint = 0
let movementDuration = 0.3
let constraint = CGFloat(up ? temporaryConstraint : originalConstraint)
containerViewConstraint.constant = constraint
UIView.animateWithDuration(movementDuration) {
self.view.layoutIfNeeded()
}
}
これは完璧に動作します。スクロールビューはテキストフィールドの位置によって大気的に調整します。
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.25;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;
@interface LoginVC ()
{
CGFloat animatedDistance;
CGRect viewFrameKey;
}
//In ViewDidLoad
viewFrameKey=self.view.frame;
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
CGRect textFieldRect =
[self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect =
[self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textFieldRect.Origin.y + 0.5 * textFieldRect.size.height;
CGFloat numerator =
midline - viewRect.Origin.y
- MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator =
(MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
* viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
{
heightFraction = 0.0;
}
else if (heightFraction > 1.0)
{
heightFraction = 1.0;
}
UIInterfaceOrientation orientation =
[[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait ||
orientation == UIInterfaceOrientationPortraitUpsideDown)
{
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
}
else
{
animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
}
CGRect viewFrame = self.view.frame;
viewFrame.Origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrameKey];
[UIView commitAnimations];
}
このクラスが見つかりました:
https://github.com/OliverLetterer/SLScrollViewKeyboardSupport
これまでのところ、アニメーションと正しいオフセットを含めて、iPhone上で非常にうまく機能しています。
それを使用するには、単にviewDidLoad
に追加します。
self.support = [[SLScrollViewKeyboardSupport alloc] initWithScrollView:self.scrollView];
非常に軽量な解決策は KeyboardAnimator を使うことです。
プロジェクトはサンプル実装を手に入れました、ドキュメンテーションはまだ進行中です...
適切な使い方:: これはUITextFieldとUITextViewのための特定の実装を持っています
制限事項:: 完全に目的語-cになっています、Swift版は近日中に公開予定です。
このコードは、キーボードの高さとテキストフィールドの奥行きに基づいて、どれだけ上に移動する必要があるかを計算します。忘れずにデリゲートを追加し、ヘッダーにUITextFieldDelegateを継承してください。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[_tbxUsername resignFirstResponder];
[_tbxPassword resignFirstResponder];
}
- (void)textFieldDidBeginEditing:(UITextField *) textField
{
[self animateTextField:textField up:YES];
}
- (void)textFieldDidEndEditing:(UITextField *) textField
{
[self animateTextField:textField up:NO];
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
int animatedDistance;
int moveUpValue = textField.frame.Origin.y+ textField.frame.size.height;
UIInterfaceOrientation orientation =
[[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait ||
orientation == UIInterfaceOrientationPortraitUpsideDown)
{
animatedDistance = 236-(460-moveUpValue-5);
}
else
{
animatedDistance = 182-(320-moveUpValue-5);
}
if(animatedDistance>0)
{
const int movementDistance = animatedDistance;
const float movementDuration = 0.3f;
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: nil context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
}
ViewDidLoadに追加するデリゲート
_tbxUsername.delegate = self;
_tbxPassword.delegate = self;
あなたのViewController上で:
@IBOutlet weak var usernameTextfield: UITextField!
@IBOutlet weak var passwordTextfield: UITextField!
@IBOutlet weak var loginScrollView: UIScrollView!
override func viewWillAppear(animated: Bool) {
loginScrollView.scrollEnabled = false
}
TextFieldデリゲートを追加します。
//MARK:- TEXTFIELD METHODS
func textFieldShouldReturn(textField: UITextField) -> Bool
{
if (usernameTextfield.resignFirstResponder())
{
passwordTextfield.becomeFirstResponder()
}
textField.resignFirstResponder();
loginScrollView!.setContentOffset(CGPoint.zero, animated: true);
loginScrollView.scrollEnabled = false
return true
}
func textFieldDidBeginEditing(textField: UITextField)
{
loginScrollView.scrollEnabled = true
if (textField.tag == 1 && (device == "iPhone" || device == "iPhone Simulator" || device == "iPod touch"))
{
let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.Origin.y/6.4);
loginScrollView!.setContentOffset(scrollPoint, animated: true);
}
else if (textField.tag == 2 && (device == "iPhone" || device == "iPhone Simulator" || device == "iPod touch"))
{
let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.Origin.y/6.0);
loginScrollView!.setContentOffset(scrollPoint, animated: true);
}
}
func textFieldDidEndEditing(textField: UITextField)
{
loginScrollView!.setContentOffset(CGPointZero,animated: true);
}
Scrollviewをビューに設定
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
CGPoint point;
if(textField == txtEmail){
// -90 is for my you can change as per your postion
point = CGPointMake(0, textField.frame.Origin.y - 90);
}
else if (textField == txtContact){
point = CGPointMake(0, textField.frame.Origin.y - 90);
}
[scrollV setContentOffset:point animated:YES];
}
IPadでスクロールアップするには、テキストフィールドのデリゲートメソッドにこれらの行を追加してください。
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeTextfield = textField;
CGPoint pt;
CGRect rc = [textField bounds];
rc = [textField convertRect:rc toView:scrlView];
pt = rc.Origin;
pt.x = 0;
pt.y -= 100;
[scrlView setContentOffset:pt animated:YES];
scrlView.contentSize = CGSizeMake(scrlView.frame.size.width, button.frame.Origin.y+button.frame.size.height + 8 + 370);
}
IQKeyboardライブラリを試してください。
これは自動的にテキストフィールドを上に移動します。
これは、制約を使用して以下のコード行で簡単に達成できます
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
[self adjustTextViewByKeyboardState:YES keyboardInfo:[notification userInfo]];
}
- (void)keyboardWillHide:(NSNotification *)notification {
[self adjustTextViewByKeyboardState:NO keyboardInfo:[notification userInfo]];
}
- (void)viewDidDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super viewDidDisappear:animated];
}
- (void)adjustTextViewByKeyboardState:(BOOL)showKeyboard keyboardInfo:(NSDictionary *)info {
CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat height = keyboardFrame.size.height;
self.constraintToAdjust.constant = height; UIViewAnimationCurve animationCurve = [info[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue];
UIViewAnimationOptions animationOptions = UIViewAnimationOptionBeginFromCurrentState;
if (animationCurve == UIViewAnimationCurveEaseIn) {
animationOptions |= UIViewAnimationOptionCurveEaseIn;
}
else if (animationCurve == UIViewAnimationCurveEaseInOut) {
animationOptions |= UIViewAnimationOptionCurveEaseInOut;
}
else if (animationCurve == UIViewAnimationCurveEaseOut) {
animationOptions |= UIViewAnimationOptionCurveEaseOut;
}
else if (animationCurve == UIViewAnimationCurveLinear) {
animationOptions |= UIViewAnimationOptionCurveLinear;
}
[UIView animateWithDuration:[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0 options:animationOptions animations:^{
[self.view layoutIfNeeded];
} completion:nil];
}
隠れている正確な交差領域(キーボードの枠とテキストフィールドの枠)を計算してから、ビューの枠を変更する必要があります。
ここで私は完全な例を挙げています。
3つの変数を宣言する
#define PADDING 10
@interface PKViewController () @property (nonatomic, assign) CGRect originalViewFrame; //original view's frame @property (nonatomic, strong) UITextField *activeTextField; // current text field @property (nonatomic, assign) CGRect keyBoardRect; // covered area by keaboard @end
オリジナルフレームを保存
- (void)viewDidLoad {
[super viewDidLoad];
_originalViewFrame = self.view.frame;
}
View Controllerをキーボード通知用のオブザーバとして追加する
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
オブザーバを削除
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
表示されたらキーボードで覆われた領域を保存し、表示されなくなったらCGRectZeroに設定します
- (void)keyboardWasShown:(NSNotification *)notification{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
_keyBoardRect = CGRectMake(0, _originalViewFrame.size.height - keyboardSize.height, keyboardSize.width, keyboardSize.height);
[self moveTextFieldUP];
}
- (void) keyboardWillHide:(NSNotification *)notification{
_keyBoardRect = CGRectZero;
[self setDefaultFrame];
}
アクティブなテキストフィールドを保存する
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
_activeTextField = textField;
//When keyboard is already present but the textfield is hidden. Case:When return key of keyboard makes the next textfield as first responder
if (!CGRectIsEmpty(_keyBoardRect)) {
[self moveTextFieldUP];
}
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
今度はビューのフレームを変更する必要があります
- (void)moveTextFieldUP{
CGRect virtualTextFieldRect = CGRectMake(0, self.view.frame.Origin.y, _activeTextField.frame.size.width, _activeTextField.frame.Origin.y+_activeTextField.frame.size.height);
if (CGRectIntersectsRect(_keyBoardRect, virtualTextFieldRect)) {
CGRect intersectRect = CGRectIntersection(_keyBoardRect, virtualTextFieldRect);
CGFloat newY = _originalViewFrame.Origin.y - intersectRect.size.height;
CGFloat newHeight = _originalViewFrame.size.height + intersectRect.size.height;
CGRect newFrame = CGRectMake(0, newY-PADDING, _originalViewFrame.size.width, newHeight+PADDING);
[UIView animateWithDuration:0.3 animations:^{
[self.view setFrame:newFrame];
}];
NSLog(@"Intersect");
}
}
- (void)setDefaultFrame {
[UIView animateWithDuration:0.3 animations:^{
[self.view setFrame:_originalViewFrame];
}];
}
ここにはたくさんの答えがありますが、これはうまくいき、他のものよりはるかに短いのです。
- (void)textFieldDidBeginEditing:(UITextField *)sender
{
UIScrollView *scrollView = (UIScrollView *)self.view; // assuming this method is pasted into the UIScrollView's controller
const double dontHardcodeTheKeyboardHeight = 162;
double textY = [sender convertPoint:CGPointMake(0, 0) toView:scrollView].y;
if (textY - scrollView.contentOffset.y + sender.frame.size.height > self.view.frame.size.height - dontHardcodeTheKeyboardHeight)
[scrollView setContentOffset:CGPointMake(0.0, textY - 10) animated:YES];
}
簡単かつ自動的に そのテキストフィールドがテーブルのセル内にある場合(table.scrollable = NOの場合でも)。
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
[self slideUp];
return YES;
}
-(BOOL) textFieldShouldEndEditing:(UITextField *)textField {
[self slideDown];
return YES;
}
#pragma mark - Slide Up and Down animation
- (void) slideUp {
[UIView beginAnimations:nil context:nil];
layoutView.frame = CGRectMake(0.0, -70.0, layoutView.frame.size.width, layoutView.frame.size.height);
[UIView commitAnimations];
}
- (void) slideDown {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelay: 0.01];
layoutView.frame = CGRectMake(0.0, 0.0, layoutView.frame.size.width, layoutView.frame.size.height);
[UIView commitAnimations];
}
このスレッドには十分な答えがありますが、Appleがキーパッドの高さを考慮に入れるのと同じように、もっと単純でありながら一般化された方法をお勧めします。 Appleのアプローチ ここ にはいくつか問題がある。
これが私のアプローチです(Appleのやり方を少し修正しました) -
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
}
それは簡単です:-
TextFieldDidBeginEditingの場合: -
self.view.frame=CGRectMake(self.view.frame.Origin.x, self.view.frame.Origin.y-150, self.view.frame.size.width, self.view.frame.size.height);
TextFieldShouldEndEditingでは、 -
self.view.frame=CGRectMake(self.view.frame.Origin.x, self.view.frame.Origin.y+150, self.view.frame.size.width, self.view.frame.size.height);
IQKeyboardManagerを使用して、キーボードが表示されるとUITextFieldとUITextViewは自動的にスクロールします。 Gitリンク: https://github.com/hackiftekhar/IQKeyboardManager 。
ポッド:ポッド 'IQKeyboardManager'#iOS8以降
ポッド 'IQKeyboardManager'、 '3.3.7'#iOS7
TextFieldsを使ったScrollviewのための簡単な解決法は以下の通りです、何の制約もアクティブなテキストフィールドなども必要ありません...
override func viewWillAppear(_ animated: Bool){
super.viewWillAppear(animated)
registerForKeyboardNotifications();
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
deregisterFromKeyboardNotifications();
}
//MARK:- KEYBOARD DELEGATE METHODS
func registerForKeyboardNotifications(){
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func deregisterFromKeyboardNotifications(){
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func keyboardWasShown(notification: NSNotification){
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
var contentInset:UIEdgeInsets = self.scrRegister.contentInset
contentInset.bottom = (keyboardSize?.height)!
scrRegister.contentInset = contentInset
}
func keyboardWillBeHidden(notification: NSNotification)
{
var contentInset:UIEdgeInsets = self.scrRegister.contentInset
contentInset.bottom = 0
scrRegister.contentInset = contentInset
}
1つのビューを配置してからそのビューにテキストフィールドを配置し、キーボードが表示されたときにデリゲートによってイベントを検出します。そのビューのある位置も)、それからあなたのビューはその位置に上がるでしょう。ビューをアニメートするのと同じことです。
ありがとう
Swift 3.0バージョン Applesのキーボード管理コードはこちら: FloatingTF 以下のコードで使用されているのは、iOSのマテリアルデザインベースのテキストフィールドです。
import UIKit
class SignupViewController: UIViewController, UITextFieldDelegate {
//MARK: - IBOutlet:
@IBOutlet weak var emailTF: FloatingTF!
@IBOutlet weak var passwordTF: FloatingTF!
@IBOutlet weak var dobTF: FloatingTF!
@IBOutlet weak var scrollView: UIScrollView!
//MARK: - Variable:
var activeTextField: UITextField!
//MARK: - ViewController Lifecycle:
override func viewDidLoad() {
super.viewDidLoad()
emailTF.delegate = self
passwordTF.delegate = self
dobTF.delegate = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
registerKeyboardNotifications()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
deRegisterKeyboardNotifications()
}
//MARK: - Keyboard notification observer Methods
fileprivate func registerKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
fileprivate func deRegisterKeyboardNotifications() {
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: self.view.window)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: self.view.window)
}
func keyboardWillShow(notification: NSNotification) {
let info: NSDictionary = notification.userInfo! as NSDictionary
let value: NSValue = info.value(forKey: UIKeyboardFrameBeginUserInfoKey) as! NSValue
let keyboardSize: CGSize = value.cgRectValue.size
let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
// If active text field is hidden by keyboard, scroll it so it's visible
// Your app might not need or want this behavior.
var aRect: CGRect = self.view.frame
aRect.size.height -= keyboardSize.height
let activeTextFieldRect: CGRect? = activeTextField?.frame
let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.Origin
if (!aRect.contains(activeTextFieldOrigin!)) {
scrollView.scrollRectToVisible(activeTextFieldRect!, animated:true)
} }
func keyboardWillHide(notification: NSNotification) {
let contentInsets: UIEdgeInsets = .zero
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
//MARK: - UITextField Delegate Methods
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == emailTF {
passwordTF.becomeFirstResponder()
}
else if textField == passwordTF {
dobTF.becomeFirstResponder()
}
else {
self.view.endEditing(true)
}
return true
}
func textFieldDidBeginEditing(_ textField: UITextField) {
activeTextField = textField
scrollView.isScrollEnabled = true
}
func textFieldDidEndEditing(_ textField: UITextField) {
activeTextField = nil
scrollView.isScrollEnabled = false
}
}
これは私のために働いた:
func setupKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWasShown:"), name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillBeHidden:"), name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWasShown(aNotification:NSNotification) {
let info = aNotification.userInfo
let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
let kbSize = infoNSValue.CGRectValue().size
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.3)
var rect : CGRect = self.view.frame
rect.size.height -= kbSize.height
self.view.frame = rect
UIView.commitAnimations()
}
func keyboardWillBeHidden(aNotification:NSNotification) {
let info = aNotification.userInfo
let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
let kbSize = infoNSValue.CGRectValue().size
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.3)
var rect : CGRect = self.view.frame
rect.size.height += kbSize.height
self.view.frame = rect
UIView.commitAnimations()
}
テキストフィールドを画面の一番下に配置する必要がある場合、最も不思議な解決策は、ビューコントローラを次のように上書きすることです。
override var inputAccessoryView: UIView? {
return <yourTextField>
}
Swift 4.1用のコードをユーザー入力できます
let keyBoardSize = 80.0
func keyboardWillShow() {
if view.frame.Origin.y >= 0 {
viewMovedUp = true
}
else if view.frame.Origin.y < 0 {
viewMovedUp = false
}
}
func keyboardWillHide() {
if view.frame.Origin.y >= 0 {
viewMovedUp = true
}
else if view.frame.Origin.y < 0 {
viewMovedUp = false
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if sender.isEqual(mailTf) {
//move the main view, so that the keyboard does not hide it.
if view.frame.Origin.y >= 0 {
viewMovedUp = true
}
}
}
func setViewMovedUp(_ movedUp: Bool) {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.3)
// if you want to slide up the view
let rect: CGRect = view.frame
if movedUp {
rect.Origin.y -= keyBoardSize
rect.size.height += keyBoardSize
}
else {
// revert back to the normal state.
rect.Origin.y += keyBoardSize
rect.size.height -= keyBoardSize
}
view.frame = rect
UIView.commitAnimations()
}
func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
}
func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}
(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
if (textField.frame.Origin.y > self.view.frame.size.height - 216)
{
if (screenHeight>500)
scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 100);
else
scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 216);
CGPoint scrollPoint = CGPointMake(0.0,(textField.frame.Origin.y - (self.view.frame.size.height - 216 - textField.frame.size.height - 20)));
[scrollView setContentOffset:scrollPoint animated:YES];
}
[scrollView setScrollEnabled:YES];
keyBoardを辞任するときあなたは以下のコードを書く必要があります
scrollView.contentSize = CGSizeMake(0.0, 640);
CGPoint scrollPoint = CGPointMake(0.0,0.0);
[scrollView setContentOffset:scrollPoint animated:YES];
Swift Developerの場合、Swift 3を使用して、レポがあります https://github.com/jamesrochabrun/KeyboardWillShow
import UIKit
class ViewController: UIViewController {
//1 Create a view that will hold your TEXTFIELD
let textField: UITextField = {
let tf = UITextField()
tf.translatesAutoresizingMaskIntoConstraints = false
tf.layer.borderColor = UIColor.darkGray.cgColor
tf.layer.borderWidth = 3.0
return tf
}()
//2 global variable that will hold the bottom constraint on changes
var textfieldBottomAnchor: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
//3 add the view to your controller
view.addSubview(textField)
textField.heightAnchor.constraint(equalToConstant: 80).isActive = true
textField.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
textField.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
textfieldBottomAnchor = textField.bottomAnchor.constraint(equalTo: view.bottomAnchor)
textfieldBottomAnchor?.isActive = true
setUpKeyBoardObservers()
}
//4 Use NSnotificationCenter to monitor the keyboard updates
func setUpKeyBoardObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
//5 toggle the bottom layout global variable based on the keyboard's height
func handleKeyboardWillShow(notification: NSNotification) {
let keyboardFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? CGRect
if let keyboardFrame = keyboardFrame {
textfieldBottomAnchor?.constant = -keyboardFrame.height
}
let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
if let keyboardDuration = keyboardDuration {
UIView.animate(withDuration: keyboardDuration, animations: {
self.view.layoutIfNeeded()
})
}
}
func handleKeyboardWillHide(notification: NSNotification) {
textfieldBottomAnchor?.constant = 0
let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
if let keyboardDuration = keyboardDuration {
UIView.animate(withDuration: keyboardDuration, animations: {
self.view.layoutIfNeeded()
})
}
}
//6 remove the observers
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
}
IOSでは、キーボードを上に動かしてアプリ内のテキストフィールドに戻すことは少し混乱し、同じ方法をいくつか実装する必要があります。テキストフィールドが存在するすべてのクラスで繰り返されます。
私はこのGithubコントロールを使用することを好みます。
その中で私たちは何もする必要はありません。 - ドロップコントロール をプロジェクトにドラッグ&ビルドするだけです。 - それはあなたのアプリのためにすべてをするでしょう。
ありがとう
これは役に立つでしょう。
私が使い始めた解決策は@DK_であることがわかりました。ただし、scrollViewがビュー全体をカバーするという仮定があります。そうではありませんでした。キーボードがログイン画面の下のテキストフィールドを覆っている場合に備えて、私はscrollViewが欲しいだけでした。そのため、私のコンテンツビューは私のスクロールビューと同じサイズで、メインビューより小さかった。
それはまた私が最初にトラブルに遭遇した場所である風景を説明しませんでした。数日間それを試した後、これは私のkeyboardWasShown:
メソッドです。
- (void)keyboardWasShown:(NSNotification*)aNotification
{
// A lot of the inspiration for this code came from http://stackoverflow.com/a/4837510/594602
CGFloat height = 0;
NSDictionary* info = [aNotification userInfo];
CGRect kbFrameRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect kbBoundsRect = [self.view convertRect:kbFrameRect fromView:nil]; // Convert frame from window to view coordinates.
CGRect scrollRect = scrollView.frame;
CGRect intersect = CGRectIntersection(kbBoundsRect, scrollRect);
if (!CGRectIsNull(intersect))
{
height = intersect.size.height;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, height, 0.0);
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
// Figure out what the view rectangle is for the scrollView
CGPoint contentOffset = scrollView.contentOffset;
CGRect visibleRect = CGRectOffset(scrollRect, contentOffset.x, contentOffset.y); // I'm not 100% sure if this is needed/right. My scrollView was always at the top in testing.
visibleRect.size.height -= height;
CGRect activeRect = activeField.frame;
if (!CGRectContainsRect(visibleRect, activeRect))
{
[self.scrollView scrollRectToVisible:activeField.frame animated:YES];
}
}
また、自動レイアウトを使用するのに苦労しました。レイアウトが正しく行われていないと、思ったようにスクロールしません。もっと楽になりました1つのことは、スクロールされることになっていたすべての項目を単一のビューに配置し、それをスクロールビューの唯一の項目として配置することでした。私はその単一のビューを「コンテンツビュー」と呼びました。
重要なのは、コンテンツビューの幅と高さが設定されていることです。これにより、スクロールビューは処理する必要があるコンテンツの量を正確に知ることができました。これは通常のレイアウトから少し後退したものです。通常、ビューはできるだけ多くのスペースを取ろうとしています。スクロールビューの内容を使用して、ビューをできるだけ閉じ込めるようにします。コンテンツビューでは、これをやめることができます。だから私は248の高さを私に与え、そして私の幅として320の標準スクリーン幅を使った。
最終的に私のために働いたレイアウトはこれらでした:
Horizontal Space - View - Scroll View
(0)Vertical Space - View - Scroll View
(0)Horizontal Space - Scroll View - View
(0)Height - (248) - Scroll View
Vertical Space - View - Scroll View
(0)Vertical Space - Scroll View - View
(0)Horizontal Space - View - Scroll View
(0)Horizontal Space - Scroll View - View
(0)Height - (248) - View
Width - (320) - View
あなたはこの単純なGitリポジトリを使うことができます: https://github.com/hackiftekhar/IQKeyboardManager
これは自動的にすべてのフィールドの移動を管理するライブラリです。
彼らのreadmeによると、統合はとても簡単です。
コードを入力する必要はありませんおよび追加の設定は不要です。 IQKeyboardManagerを使用するには、単にプロジェクトにソースファイルを追加する必要があります
ただし、これは非常に優れた制御方法ですが、スクロールビューを使用するView Controllerの場合のように、競合が発生することがあります。コンテンツサイズが変わることがあります。それでも、あなたはそれのために行くことができ、あなたの要求に従ってそれを試すことができます多分あなたは私が逃したことをすることができました。
ライブおよびロードされたiphoneのUICatalogView
の例を参照してください。
テキストフィールドの変更や内容の編集中にデフォルトのメインビューにリセットすると問題が発生しました(たとえば、電話テキストフィールドと ' - '記号を追加し、ビューがテキストフィールドを覆って戻る)次のように、通知デリゲート関数内のフレームサイズや位置ではなく、レイアウトや変更の制約が一定です。
P.S私は単純にビューを上に移動するだけでscrollviewを使用していませんが、それは同様に動作するはずです
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if !keyboardIsShown{
self.infoViewTopConstraint.constant -= keyboardSize.height
self.infoViewBottomConstraint.constant += keyboardSize.height
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
keyboardIsShown = true
}
}
func keyboardWillHide(notification: NSNotification) {
if keyboardIsShown {
self.infoViewTopConstraint.constant += keyboardSize.height
self.infoViewBottomConstraint.constant -= keyboardSize.height
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
keyboardIsShown = false
}
この質問にはすでにたくさんの答えがあります。ある人はスクロールビューを使うと言い、ある人は第3のライブラリを使うと言いました。
しかし、私にとっては、解決策は静的セルを含むUITableViewController
であるべきです。
あなたはUIを複数の部分に分けてそれらを一つずつtableViewCellsに入れるでしょう、もうあなたはキーボードを心配する必要はなく、tableViewControllerはあなたのためにそれを自動的に管理します。
パディング、マージン、セルの高さを計算するのは少し難しいかもしれませんが、あなたの数学が問題なければ、それは簡単です。
私はSwiftと自動レイアウトを使います(しかし、前のSwiftの答えについてはコメントできません)。スクロールビューを使わずにこれを行う方法は次のとおりです。
私は自分のフォームをフィールド間に垂直方向の制約を付けてIBでレイアウトし、それらを分離します。一番上のフィールドからコンテナビューに垂直方向の拘束を追加し、それに対するアウトレットを作成します(以下のコードではtopSpaceForFormConstraint)。必要なのは、この制約を更新することだけです。これは、Niceソフトモーション用のアニメーションブロックで行います。高さのチェックはもちろんオプションです、この場合、私はちょうど最小の画面サイズのためにそれをする必要がありました。
これは通常のtextFieldDidBeginEditingまたはkeyboardWillShowメソッドのいずれかを使用して呼び出すことができます。
func setFormHeight(top: CGFloat)
{
let height = UIScreen.mainScreen().bounds.size.height
// restore text input fields for iPhone 4/4s
if (height < 568) {
UIView.animateWithDuration(0.2, delay: 0.0, options: nil, animations: {
self.topSpaceForFormConstraint.constant = top
self.view.layoutIfNeeded()
}, completion: nil)
}
}
この可能性はここでは見られなかったので、答えでメソッドを試したが、数時間後にiOS6/7のXCode 5に はるか より簡単な方法があることを発見したので追加します。 NSLayoutConstraintsを使用してください。
参照項目: 自動レイアウト制限 - キーボード
これが私のコードです:
.mファイル:
// Called when the UIKeyboardWillShowNotification is sent.
- (void)keyboardWillBeShown:(NSNotification*)aNotification
{
NSLog(@"keyboardWillBeShown:");
[self.PhoneNumberLabelOutlet setHidden:TRUE];
CGFloat heightOfLabel = self.PhoneNumberLabelOutlet.frame.size.height;
for( NSLayoutConstraint* thisConstraint in self.topElementsVerticalDistanceFromTopLayoutConstraint ) {
thisConstraint.constant -= heightOfLabel;
}
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGFloat oldConstant = [self.SignInYConstraint constant];
self.SignInYConstraint.constant = oldConstant + kbSize.height;
[self.view setNeedsUpdateConstraints];
NSTimeInterval duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:duration animations:^{
[self.view layoutIfNeeded];
}];
}
.hファイル:
#import <UIKit/UIKit.h>
@interface SignInViewController : UIViewController {
UITextField* _activeField;
}
- (void)signInCallback:(NSObject*)object;
@property (weak, nonatomic) IBOutlet UILabel *PhoneNumberLabelOutlet;
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *ActivityIndicatorOutlet;
@property (weak, nonatomic) IBOutlet UITextField *UserIDTextfieldOutlet;
@property (weak, nonatomic) IBOutlet UITextField *PasswordTextfieldOutlet;
@property (weak, nonatomic) IBOutlet UIButton *SignInButton;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *SignInYConstraint;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *topElementsVerticalDistanceFromTopLayoutConstraint;
@end
Swift 5
viewDidLoadまたはviewDidAppear add addKeyboardObserversメソッドで。
fileprivate func addKeyboardObservers(){
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
fileprivate func removeKeyboardObservers(){
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
}
@objc fileprivate func keyboardWillHide(_ notification: Notification){
if (window == nil) {return}
guard let duration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {return}
scrollView.contentInset.bottom = .zero
}
@objc fileprivate func keyboardWillShow(_ notification: Notification){
if (window == nil) {return}
if UIApplication.shared.applicationState != .active { return }
// keyboard height
guard let height = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height else {return}
// keyboard present animation duration
guard let duration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {return}
scrollView.contentInset.bottom = height
}
deinitでオブザーバーを削除するか、消えることを忘れないでください
self.removeKeyboardObservers()
私は少し遅れています。あなたのviewControllerにscrollViewを追加する必要があります。
2以下の方法で実施する必要があります。
TextFieldデリゲートメソッド。
- (void)textFieldDidBeginEditing:(UIView *)textField {
[self scrollViewForTextField:reEnterPINTextField];
}
そして、デリゲートメソッドで以下のメトンを呼び出します。
- (void)scrollViewForTextField:(UIView *)textField {
NSInteger keyboardHeight = KEYBOARD_HEIGHT;
if ([textField UITextField.class]) {
keyboardHeight += ((UITextField *)textField).keyboardControl.activeField.inputAccessoryView.frame.size.height;
}
CGRect screenFrame = [UIScreen mainScreen].bounds;
CGRect aRect = (CGRect){0, 0, screenFrame.size.width, screenFrame.size.height - ([UIApplication sharedApplication].statusBarHidden ? 0 : [UIApplication sharedApplication].statusBarFrame.size.height)};
aRect.size.height -= keyboardHeight;
CGPoint relativeOrigin = [UIView getOriginRelativeToScreenBounds:textField];
CGPoint bottomPointOfTextField = CGPointMake(relativeOrigin.x, relativeOrigin.y + textField.frame.size.height);
if (!CGRectContainsPoint(aRect, bottomPointOfTextField) ) {
CGPoint scrollPoint = CGPointMake(0.0, bottomPointOfTextField.y -aRect.size.height);
[contentSlidingView setContentOffset:scrollPoint animated:YES];
}
}
私の5セントを追加してください:)
私はいつもinputTextFieldまたはscrollViewのためにtableViewを使うことを好みます。通知と組み合わせると、そのような動作を簡単に管理できます。 (TableViewで静的セルを使用する場合は、このような動作が自動的に管理されます。)
// MARK: - Notifications
fileprivate func registerNotificaitions() {
NotificationCenter.default.addObserver(self, selector: #selector(AddRemoteControlViewController.keyboardWillAppear(_:)),
name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(AddRemoteControlViewController.keyboardWillDisappear),
name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
fileprivate func unregisterNotifications() {
NotificationCenter.default.removeObserver(self)
}
@objc fileprivate func keyboardWillAppear(_ notification: Notification) {
if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
view.layoutIfNeeded()
UIView.animate(withDuration: 0.3, animations: {
let heightInset = keyboardHeight - self.addDeviceButton.frame.height
self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: heightInset, right: 0)
self.view.layoutIfNeeded()
}, completion: nil)
}
}
@objc fileprivate func keyboardWillDisappear() {
view.layoutIfNeeded()
UIView.animate(withDuration: 0.3, animations: {
self.tableView.contentInset = UIEdgeInsets.zero
self.view.layoutIfNeeded()
}, completion: nil)
}