Подтвердить что ты не робот

Показать клавиатуру с UITextField в представлении вспомогательного входа

У меня есть кнопка A, и когда нажата кнопкаA, я хочу, чтобы клавиатура отображалась с помощью UITextField в inputAccessoryView. Есть ли способ показать клавиатуру вручную, а также установить inputAccessoryView без первоначального UITextField?

Спасибо.

4b9b3361

Ответ 1

Вы не можете вызвать клавиатуру без объекта, который может стать первым ответчиком. Существует два способа обойти:

  • Подкласс a UIView и реализовать в нем протокол UIKeyInput. Например:

    В вашем .h файле:

    @interface InputObject : UIView<UIKeyInput>
    @property (nonatomic, copy) NSString *text;
    @property (nonatomic, strong) UIView *inputAccessoryView; // You must override inputAccessoryView , since it readonly by default
    @end
    

    В вашем .m файле выполните протокол:

    - (BOOL)canBecomeFirstResponder
    {
        return YES;
    }
    
    - (BOOL)hasText
    {
        return [self.text length];
    }
    
    - (void)insertText:(NSString *)text
    {
        NSString *selfText = self.text ? self.text : @"";
        self.text = [selfText stringByAppendingString:text];
        [[NSNotificationCenter defaultCenter] postNotificationName:kInputObjectTextDidChangeNotification object:self];
    }
    
    - (void)deleteBackward
    {
        if ([self.text length] > 0)
            self.text = [self.text substringToIndex:([self.text length] - 1)];
        else
            self.text = nil;
        [[NSNotificationCenter defaultCenter] postNotificationName:kInputObjectTextDidChangeNotification object:self];
    }
    

Предположим, вы хотите вызвать клавиатуру в -viewDidAppear:, код будет выглядеть следующим образом:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // inputObject and textField are both your ivars in your view controller
        inputObject = [[InputObject alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
        textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 30)];
        inputObject.inputAccessoryView = textField;
        [self.view addSubview:inputObject];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(inputObjectTextDidChange:) name:kInputObjectTextDidChangeNotification object:nil];

    }

    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
        [inputObject becomeFirstResponder]; // This will summon the keyboard
    }

Затем выполните селектор уведомлений в контроллере вида:

    - (void)inputObjectTextDidChange:(NSNotification *)notification
    {
        // Just set the text here. notification.object is actually your inputObject.
        textField.text = ((InputObject *)(notification.object)).text;
    }

Это, вероятно, то, что вы подразумеваете под ", установите inputAccessoryView без первоначального UITextField"

  • Другим обходным решением является позволить textField "притворяться" inputAccessoryView, тщательно упорядочив его анимацию. Но для этого решения ваш текстовый фильтр должен быть первым ответчиком.

Во-первых, вы наблюдаете события клавиатуры в своем -viewDidLoad:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Init the textField and add it as a subview of self.view
        textField = [[UITextField alloc] init];
        textField.backgroundColor = [UIColor redColor];
        [self.view addSubview:textField];

        // Register keyboard events
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShowNotification:) name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHideNotification:) name:UIKeyboardWillHideNotification object:nil];
    }

Во-вторых, установите фрейм вашего textField в -viewWillAppear:, чтобы гарантировать, что его фрейм не будет влиять на автоматизацию:

    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        textField.frame = CGRectMake(0, CGRectGetMaxY(self.view.bounds), CGRectGetWidth(self.view.bounds), 50);
    }

А затем расположите анимацию textField и позвольте ей синхронизироваться с анимацией клавиатуры. Селектора уведомлений клавиатуры могут быть такими:

    - (void)keyboardWillShowNotification:(NSNotification *)notification
    {
        NSDictionary *userInfo = notification.userInfo;
        UIViewAnimationCurve curve = [[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
        CGFloat duration = [[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
        CGRect keyboardFrame = [[userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
        keyboardFrame = [self.view convertRect:keyboardFrame toView:self.view];

        [UIView animateWithDuration:duration delay:0.0f options:(UIViewAnimationOptions)curve animations:^{
            CGRect textFieldFrame = textField.frame;
            textFieldFrame.origin.y = keyboardFrame.origin.y - CGRectGetHeight(textFieldFrame);
            textField.frame = textFieldFrame;
        }completion:nil];
    }

    - (void)keyboardWillHideNotification:(NSNotification *)notification
    {
        NSDictionary *userInfo = notification.userInfo;
        UIViewAnimationCurve curve = [[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
        CGFloat duration = [[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
        [UIView animateWithDuration:duration delay:0.0f options:(UIViewAnimationOptions)curve animations:^{
            textField.frame = CGRectMake(0, CGRectGetMaxY(self.view.bounds), CGRectGetWidth(self.view.bounds), 50);
        }completion:nil];
    }

Наконец, вызовите [textField becomeFirstResponder], чтобы запустить анимацию.

Ответ 2

Другим решением является добавление этих методов в реализацию UIViewController:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self reloadInputViews];
}

- (BOOL)canBecomeFirstResponder {
    return YES;
}

- (UIView *)inputAccessoryView {
    if (!_textField) {
        _textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
        _textField.backgroundColor = [UIColor whiteColor];
        _textField.delegate = self;
    }
    return _textField;
}

#pragma mark - UITextFieldDelegate

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return YES;
}

и добавьте переменную _textField к вашему интерфейсу:

@interface ViewController : UIViewController <UITextFieldDelegate> {
    UITextField *_textField;
}
@end

Ответ 3

Хакерным решением этой проблемы будет использование UITextField в представлении, но скрытое, а затем вызов [textfield getFirstResponder] на нем.

Я только что протестировал его, и это работает

UITextField * randofield = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
[self.view addSubview:randofield];
// doesn't have to be hidden... but to be safe.
randofield.hidden = YES;
[randofield becomeFirstResponder];

Вы должны иметь это подвид представления, иначе это не сработает.

Ответ 4

версия Swift с использованием ограничений автоопределения на основе ответа liuyaodong.

Требуется установить настройку ограничения вертикального пространства между нижней частью экрана и текстом. Обратите внимание, что установка смещения должна происходить вне контекста анимации, и только макет происходит внутри контекста анимации.

@IBOutlet weak var textViewBottomOffsetConstraint: NSLayoutConstraint!

override public func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}

func keyboardWillHide(notification: NSNotification) {
    guard let userInfo = notification.userInfo else {
        return
    }

    animateTextFieldOffset(0, userInfo: userInfo)
}

func keyboardWillShow(notification: NSNotification) {
    guard let userInfo = notification.userInfo, var keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() else {
        return
    }

    keyboardFrame = view.convertRect(keyboardFrame, toView: view)

    animateTextFieldOffset(keyboardFrame.size.height, userInfo: userInfo)
}

func animateTextFieldOffset(offset: CGFloat, userInfo: [NSObject: AnyObject] ){
    guard let animationCurveInt = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int, let animationCurve = UIViewAnimationCurve(rawValue:animationCurveInt) else { return }

    guard let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double else { return }

    self.loginViewBottomOffsetConstraint.constant = offset

    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationDuration(animationDuration)
    UIView.setAnimationCurve(animationCurve)
    UIView.setAnimationBeginsFromCurrentState(true)
    self.view.layoutIfNeeded()
    UIView.commitAnimations()
}