UITextField: перемещение вида при появлении клавиатуры



в настоящее время я работаю над приложением для iPhone с одним представлением, которое имеет несколько полей UITextFields для ввода. Когда клавиатура показывает, она накладывает нижние текстовые поля. Поэтому я добавил соответствующий textFieldDidBeginEditing: метод, чтобы переместить вид, который отлично работает:



- (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];
}
}


этот метод проверяет, является ли источник сообщения одним из текстовых полей, которые видны при отображении клавиатуры, а если нет, то он перемещает представление вверх.



Я также добавил textFieldDidEndEnditing: способ, который снова перемещает представление вниз (и обновляет некоторые объекты модели в соответствии с измененным входом):



- (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
}


однако это решение имеет простой недостаток: когда я заканчиваю редактирование одного из "скрытых" текстовых полей и касаюсь другого текстового поля, клавиатура исчезает, вид перемещается вниз, вид снова перемещается вверх, и клавиатура снова появляется.



есть ли возможность сохранить клавиатуру от исчезновения и появления между двумя правками (из "скрытых" текстовых полей - так что просмотр перемещается только тогда, когда выбранное текстовое поле изменяется с того, что было бы скрыто клавиатурой, на то, что не было бы скрыто)?

802   6  

6 ответов:

это решение основано на Comsubvie's one.

плюсы:

  • он поддерживает вращение устройства - работает на всех направлениях;
  • он не жестко кодирует значения для продолжительности анимации и кривой, он читает их из уведомления клавиатуры;
  • он использует UIKeyboardWillShowNotification вместо UIKeyboardDidShowNotification для синхронизации анимации клавиатуры и пользовательских действий;
  • он не использует устаревшие UIKeyboardBoundsUserInfoKey;
  • он обрабатывает изменение размера клавиатуры за счет нажатия Международной клавиши;
  • исправлена утечка памяти регистрации событий клавиатуры;
  • весь код обработки клавиатуры инкапсулируется в отдельный класс -KBKeyboardHandler;
  • гибкость KBKeyboardHandler класс может быть легко расширен / изменен для лучшего удовлетворения конкретных потребностей;

ограничения:

  • работает для iOS 4 и выше, он нуждается в небольших модификациях для поддержки старых версии;
  • это работает для приложений с одним UIWindow. Если вы используете несколько UIWindows, вам может потребоваться изменить retrieveFrameFromNotification: метод.

использование:

Включить KBKeyboardHandler.h, KBKeyboardHandler.m и KBKeyboardHandlerDelegate.h в вашем проекте. Реализовать KBKeyboardHandlerDelegate протокол в вашем контроллере вида-он состоит из одного метода, который будет вызываться, когда клавиатура отображается, скрыта или ее размер изменяется. Создайте экземпляр KBKeyboardHandler и установить его представителя (как правило). См. пример MyViewController ниже.

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.м:

#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

пример MyViewController.h:

@interface MyViewController : UIViewController<KBKeyboardHandlerDelegate>
...
@end

пример MyViewController.м:

@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;
}

обновление: исправлено iOS 7 предупреждение, спасибо @weienv.

Я только что решил эту проблему. Решение представляет собой комбинацию a UIKeyboardDidShowNotification и UIKeyboardDidHideNotification наблюдатель с выше textFieldDidBeginEditing: и textFieldDidEndEditing: методы.

вам нужно три дополнительные переменные, одна для хранения текущего выбранного UITextField (который я назвал activeField), один, чтобы указать, если текущий вид был перемещен, и один, чтобы указать, если клавиатура отображается.

вот как эти двое UITextField методы делегата выглядят так:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    activeField = textField;
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    activeField = nil;
    // Additional Code
}

когда представление загружается, создаются следующие два наблюдателя:

- (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];
}

и соответствующие методы реализуются следующим образом:

- (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;
}

этот код работает, как ожидалось. Клавиатура отключается только при нажатии кнопки "Готово", в противном случае она остается видимой, и вид не перемещается.

в качестве дополнительного Примечания, я думаю, что можно получить animationDuration динамически, попросив NSNotification "объект", так как я уже играл с аналогичное решение, но не заставило его работать (что он делает сейчас).

этот контроллер вида должен быть UITextView делегат, и вы должны установить self.textview.delegate = self на 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];
}

у меня есть ваша проблема просто сделать простую вещь просто дайте выход UIScrollview. установите уникальное свойство тега для каждого текстового поля в представлении.

-(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.
    }
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);
    }];
}

довольно простое решение, работает со всеми размерами экрана

сначала вы должны встроить вас UITextFields в UIScrollView. В моем случае у меня было несколько UITextFields и UITextView.

enter image description here

затем вы должны наследовать от UITextFieldDelegate, UITextViewDelegate.

class SettingsVC: UIViewController, UITextFieldDelegate, UITextViewDelegate

присвоить текстовое поле и делегаты поле TextView самостоятельно.

fullNameTextField.delegate = self usernameTextField.delegate = self websiteTextField.delegate = self profileDescription.delegate = self

затем используйте этот код:

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)
  }

короче говоря, вы подписываетесь на уведомление UIKeyboardDidShow. Когда вы нажимаете на textField или textView клавиатура отображается, и вы хватаете рамку клавиатуры и рамку элемента ввода, который вы нажали. Преобразуйте их в систему координат viewController и сравните самую низкую точку входного элемента с самой высокой клавиатурой. Если нижняя часть элемента ниже, чем самая высокая клавиатура, чем установить смещение containerScrollView на разницу между их.

if editingTextInputFrame.maxY > keyboardFrame.minY{
            
            let diff = keyboardFrame.minY - editingTextInputFrame.maxY
            containerScrollView.setContentOffset(CGPoint(x: 0, y: -diff), animated: true)
            
          }

res1 res2

Comments

    Ничего не найдено.