UITextField: przesuń widok po pojawieniu się klawiatury
Obecnie pracuję nad aplikacją na iPhone ' a z jednym widokiem, która ma wiele pól UITextFields do wprowadzania. Gdy pojawi się klawiatura, nakłada się na dolne pola tekstowe. Dodałem więc odpowiednią metodę textFieldDidBeginEditing:
, aby przesunąć widok w górę, która działa świetnie:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
if ( ( textField != inputAmount ) && ( textField != inputAge ) ) {
NSTimeInterval animationDuration = 0.300000011920929;
CGRect frame = self.view.frame;
frame.origin.y -= kOFFSET_FOR_KEYBOARD;
frame.size.height += kOFFSET_FOR_KEYBOARD;
[UIView beginAnimations:@"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
}
}
Ta metoda sprawdza, czy źródłem wiadomości jest jedno z pól tekstowych, które są widoczne na klawiaturze, a jeśli nie, przesuwa widok w górę.
Dodałem również metodę textFieldDidEndEnditing:
, która przesuwa widok w dół ponownie (i aktualizuje niektóre obiekty modelu zgodnie ze zmienionym wejściem):
- (void)textFieldDidEndEditing:(UITextField *)textField {
if ( ( textField != inputMenge ) && ( textField != inputAlter ) ) {
NSTimeInterval animationDuration = 0.300000011920929;
CGRect frame = self.view.frame;
frame.origin.y += kOFFSET_FOR_KEYBOARD;
frame.size.height -= kOFFSET_FOR_KEYBOARD;
[UIView beginAnimations:@"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
}
// Additional Code
}
Jednak To rozwiązanie ma prostą wadę: kiedy skończę edytować jedno z "ukrytych" pól tekstowych i dotknę innego pola tekstowego, klawiatura znika, widok przesuwa się w dół, widok przesuwa się ponownie w górę i pojawia się klawiatura.
Czy jest jakakolwiek możliwość, aby klawiatura nie znikała i nie pojawiała się ponownie pomiędzy dwoma edycjami ("ukrytych" pól tekstowych - tak aby Widok poruszał się tylko wtedy, gdy zaznaczone textfield zmienia się z takiego, który byłby ukryty przez klawiaturę na taki, który nie byłby Ukryty)?
6 answers
To rozwiązanie opiera się na ComSubVie ' S one.
Zalety:
- Dzięki temu, że urządzenie jest w pełni kompatybilne z innymi urządzeniami]}
- Nie koduje na twardo wartości czasu trwania animacji i krzywej, odczytuje je z powiadomienia klawiatury; {21]} W przeciwieństwie do tego, że nie jest on w pełni kompatybilny z klawiaturą, nie jest on w pełni kompatybilny z klawiaturą.]}
- nie używa przestarzałego
UIKeyboardBoundsUserInfoKey
; - obsługuje zmianę rozmiaru klawiatury z powodu naciśnięcia Międzynarodowego klucz; [[20]}Naprawiono wyciek pamięci przez niezarejestrowanie zdarzeń klawiatury;
- cały kod obsługi klawiatury jest zamknięty w osobnej klasie -
KBKeyboardHandler
;
Klasa może być łatwo rozszerzona / zmodyfikowana w celu lepszego dopasowania do konkretnych potrzeb;]}
Ograniczenia:
-
[20]} Działa na iOS 4 i nowsze, wymaga niewielkich modyfikacji, aby obsługiwać starsze wersje; [21]}
- Działa dla aplikacji z pojedynczym
UIWindow
. Jeśli używasz wielu UIWindows, możesz potrzebować aby zmodyfikować metodęretrieveFrameFromNotification:
.
Użycie:
Include KBKeyboardHandler.h, KBKeyboardHandler.m i KBKeyboardHandlerDelegate.h w Twoim projekcie. Zaimplementuj protokół KBKeyboardHandlerDelegate
w kontrolerze widoku-składa się on z jednej metody, która zostanie wywołana po wyświetleniu, ukryciu klawiatury lub zmianie jej rozmiaru. Tworzy instancję KBKeyboardHandler
i ustawia jej delegata (zazwyczaj self). Zobacz przykład MyViewController
poniżej.
KBKeyboardHandler.h :
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@protocol KBKeyboardHandlerDelegate;
@interface KBKeyboardHandler : NSObject
- (id)init;
// Put 'weak' instead of 'assign' if you use ARC
@property(nonatomic, assign) id<KBKeyboardHandlerDelegate> delegate;
@property(nonatomic) CGRect frame;
@end
KBKeyboardHandler.m :
#import "KBKeyboardHandler.h"
#import "KBKeyboardHandlerDelegate.h"
@implementation KBKeyboardHandler
- (id)init
{
self = [super init];
if (self)
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
@synthesize delegate;
@synthesize frame;
- (void)keyboardWillShow:(NSNotification *)notification
{
CGRect oldFrame = self.frame;
[self retrieveFrameFromNotification:notification];
if (oldFrame.size.height != self.frame.size.height)
{
CGSize delta = CGSizeMake(self.frame.size.width - oldFrame.size.width,
self.frame.size.height - oldFrame.size.height);
if (self.delegate)
[self notifySizeChanged:delta notification:notification];
}
}
- (void)keyboardWillHide:(NSNotification *)notification
{
if (self.frame.size.height > 0.0)
{
[self retrieveFrameFromNotification:notification];
CGSize delta = CGSizeMake(-self.frame.size.width, -self.frame.size.height);
if (self.delegate)
[self notifySizeChanged:delta notification:notification];
}
self.frame = CGRectZero;
}
- (void)retrieveFrameFromNotification:(NSNotification *)notification
{
CGRect keyboardRect;
[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardRect];
self.frame = [[UIApplication sharedApplication].keyWindow.rootViewController.view convertRect:keyboardRect fromView:nil];
}
- (void)notifySizeChanged:(CGSize)delta notification:(NSNotification *)notification
{
NSDictionary *info = [notification userInfo];
UIViewAnimationOptions curve;
[[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];
NSTimeInterval duration;
[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration];
void (^action)(void) = ^{
[self.delegate keyboardSizeChanged:delta];
};
[UIView animateWithDuration:duration
delay:0.0
options:curve
animations:action
completion:nil];
}
@end
KBKeyboardHandlerDelegate.h :
@protocol KBKeyboardHandlerDelegate
- (void)keyboardSizeChanged:(CGSize)delta;
@end
Sample MyViewController.h :
@interface MyViewController : UIViewController<KBKeyboardHandlerDelegate>
...
@end
Sample MyViewController.m :
@implementation MyViewController
{
KBKeyboardHandler *keyboard;
}
- (void)dealloc
{
keyboard.delegate = nil;
[keyboard release];
[super dealloc];
}
- (void)viewDidLoad
{
[super viewDidLoad];
keyboard = [[KBKeyboardHandler alloc] init];
keyboard.delegate = self;
}
- (void)viewDidUnload
{
[super viewDidUnload];
keyboard.delegate = nil;
[keyboard release];
keyboard = nil;
}
- (void)keyboardSizeChanged:(CGSize)delta
{
// Resize / reposition your views here. All actions performed here
// will appear animated.
// delta is the difference between the previous size of the keyboard
// and the new one.
// For instance when the keyboard is shown,
// delta may has width=768, height=264,
// when the keyboard is hidden: width=-768, height=-264.
// Use keyboard.frame.size to get the real keyboard size.
// Sample:
CGRect frame = self.view.frame;
frame.size.height -= delta.height;
self.view.frame = frame;
}
Aktualizacja: Naprawiono Ostrzeżenie iOS 7, dzięki @ weienv.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-25 20:39:02
Właśnie rozwiązałem ten problem. Rozwiązanie jest kombinacją obserwatora UIKeyboardDidShowNotification
i UIKeyboardDidHideNotification
z powyższymi metodami textFieldDidBeginEditing:
i textFieldDidEndEditing:
.
Potrzebne są trzy dodatkowe zmienne, jedna do przechowywania bieżącego wybranego pola UITextField( które nazwałem activeField), jedna do wskazania, czy bieżący widok został przeniesiony, a druga do wskazania, czy klawiatura jest wyświetlana.
Tak wyglądają teraz dwie metody delegowania UITextField
:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
activeField = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
activeField = nil;
// Additional Code
}
Po załadowaniu widoku, następujące dwa tworzy się obserwatorów:
- (void)viewDidLoad {
// Additional Code
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasHidden:)
name:UIKeyboardDidHideNotification
object:nil];
}
I odpowiednie metody są zaimplementowane w następujący sposób:
- (void)keyboardWasShown:(NSNotification *)aNotification {
if ( keyboardShown )
return;
if ( ( activeField != inputAmount ) && ( activeField != inputAge ) ) {
NSDictionary *info = [aNotification userInfo];
NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;
NSTimeInterval animationDuration = 0.300000011920929;
CGRect frame = self.view.frame;
frame.origin.y -= keyboardSize.height-44;
frame.size.height += keyboardSize.height-44;
[UIView beginAnimations:@"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
viewMoved = YES;
}
keyboardShown = YES;
}
- (void)keyboardWasHidden:(NSNotification *)aNotification {
if ( viewMoved ) {
NSDictionary *info = [aNotification userInfo];
NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;
NSTimeInterval animationDuration = 0.300000011920929;
CGRect frame = self.view.frame;
frame.origin.y += keyboardSize.height-44;
frame.size.height -= keyboardSize.height-44;
[UIView beginAnimations:@"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
viewMoved = NO;
}
keyboardShown = NO;
}
Ten kod działa teraz zgodnie z oczekiwaniami. Klawiatura jest wyłączana tylko po naciśnięciu przycisku Gotowe, w przeciwnym razie pozostaje widoczna i widok nie jest przesuwany.
Jako dodatkowa uwaga, myślę, że można uzyskać animationDuration
dynamicznie pytając obiekt NSNotification
, ponieważ grałem już z podobnym rozwiązaniem, ale nie dostałem go do pracy (co robi teraz).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-21 16:22:20
Ten kontroler widoku musi być delegatem UITextView
i musisz ustawić self.textview.delegate = self
w viewdidload
-(void) textViewDidBeginEditing:(UITextView *)textView
{
NSLog(@"%f",self.view.frame.origin.y);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25f];
CGRect frame = self.view.frame;
frame.origin.y =frame.origin.y -204;
[self.view setFrame:frame];
[UIView commitAnimations];
}
-(void) textViewDidEndEditing:(UITextView *)textView
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25f];
CGRect frame = self.view.frame;
frame.origin.y = frame.origin.y + 204;
[self.view setFrame:frame];
[UIView commitAnimations];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-24 18:44:22
I got your Problem just do simple thing wystarczy dać outlet do UIScrollview. Ustaw unikalną właściwość znacznika dla każdego pola tekstowego w widoku.
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
switch (textField.tag)
{
case 2: //can be your textfiled tag
{ CGPoint scrollPoint = CGPointMake(0, yourtextfield.frame.origin.y-150);
//set figure y-150 as per your comfirt
[scrollview setContentOffset:scrollPoint animated:YES];
}break;
case 3:
{ CGPoint scrollPoint = CGPointMake(0, yourtextfield.frame.origin.y-180);
//set figure y-180 as per your comfirt
[scrollview setContentOffset:scrollPoint animated:YES];
}break;
...
}
}
-(void)textFieldDidEndEditing:(UITextField *)textField{
if(textField.tag==3){
[scrollview setContentOffset:CGPointZero animated:YES];
}
//set the last textfield when you want to disappear keyboard.
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-04 05:45:34
Write below code in your view controller. tbl is your table view.
-(void)viewWillAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
[[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
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
#pragma mark - Keyboard Methods
-(void)keyboardWillShow:(NSNotification *)notification
{
// 375 × 667 ( 750 × 1334 ) iPhone 6
//414 × 736
CGRect keyboardRect = [[[notification userInfo] valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
int H = [[UIScreen mainScreen] bounds].size.height - 64- 20 -keyboardRect.size.height;
[UIView animateWithDuration:0.5 animations:^{
tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, H, tbl.contentInset.right);
}];
}
-(void)keyboardWillChangeFrame:(NSNotification *)notification
{
CGRect keyboardRect = [[[notification userInfo] valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
// int H = IS_IPHONE_5?504-keyboardRect.size.height:416-keyboardRect.size.height;
int H = [[UIScreen mainScreen] bounds].size.height - 64- 20 -keyboardRect.size.height;
[UIView animateWithDuration:0.5 animations:^{
// scroll.frame = rect;
tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, H, tbl.contentInset.right);
}];
}
-(void)keyboardWillHide:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
// scroll.frame = rect;
tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, 0, tbl.contentInset.right);
}];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-08 05:43:04
Dość łatwe rozwiązanie, działa ze wszystkimi rozmiarami ekranu
Najpierw musisz osadzić UITextFields w UIScrollView. W moim przypadku miałem kilka UITextFields i UITextView.
Następnie musisz dziedziczyć z UITextFieldDelegate, Uitextviewdelegate.
class SettingsVC: UIViewController, UITextFieldDelegate, UITextViewDelegate
Przypisanie delegatów textfield i textview do self.
fullNameTextField.delegate = self
usernameTextField.delegate = self
websiteTextField.delegate = self
profileDescription.delegate = self
Następnie użyj tego kodu:
var editingTextInput: UIView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self,
selector: #selector(self.keyboardShown(notification:)),
name: NSNotification.Name.UIKeyboardDidShow,
object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
}
func keyboardShown(notification: NSNotification) {
if let infoKey = notification.userInfo?[UIKeyboardFrameEndUserInfoKey],
let rawFrame = (infoKey as AnyObject).cgRectValue {
let keyboardFrame = view.convert(rawFrame, to: view)
let editingTextInputFrame = self.editingTextInput.convert(self.editingTextInput.frame, to: view)
if editingTextInputFrame.maxY > keyboardFrame.minY{
let diff = keyboardFrame.minY - editingTextInputFrame.maxY
containerScrollView.setContentOffset(CGPoint(x: 0, y: -diff), animated: true)
}
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
self.editingTextInput = textField
}
func textViewDidBeginEditing(_ textView: UITextView) {
self.editingTextInput = textView
}
func textFieldDidEndEditing(_ textField: UITextField) {
containerScrollView.setContentOffset(CGPoint.zero, animated: true)
}
func textViewDidEndEditing(_ textView: UITextView) {
containerScrollView.setContentOffset(CGPoint.zero, animated: true)
}
Krótko mówiąc, subskrybujesz Powiadomienie UIKeyboardDidShow. Po dotknięciu textField lub textView zostanie wyświetlona klawiatura i chwycisz ramkę klawiatury i ramkę elementu wejściowego, na którym stuknąłeś. Konwertuj je na układ współrzędnych viewcontrollera i porównaj najniższy punkt elementu wejściowego z najwyższym punktem klawiatury. Jeśli dolna część elementu jest niższa od najwyższej klawiatury, Ustaw przesunięcie containerScrollView na różnicę między nimi.
if editingTextInputFrame.maxY > keyboardFrame.minY{
let diff = keyboardFrame.minY - editingTextInputFrame.maxY
containerScrollView.setContentOffset(CGPoint(x: 0, y: -diff), animated: true)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-05 10:03:26