【问题标题】:Show keyboard with UITextField in the input accessory view在输入附件视图中显示带有 UITextField 的键盘
【发布时间】:2013-08-15 20:36:28
【问题描述】:

我有一个 buttonA,当单击 buttonA 时,我希望键盘在 inputAccessoryView 中显示一个 UITextField。有没有办法手动显示键盘并设置 inputAccessoryView 而没有最初的 UITextField?

谢谢。

【问题讨论】:

    标签: ios uitextfield


    【解决方案1】:

    如果没有可以成为第一响应者的对象,您将无法召唤键盘。有两种解决方法:

    • 子类化 UIView 并在其中实现 UIKeyInput 协议。例如:

      在您的 .h 文件中:

      @interface InputObject : UIView<UIKeyInput>
      @property (nonatomic, copy) NSString *text;
      @property (nonatomic, strong) UIView *inputAccessoryView; // You must override inputAccessoryView , since it's 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;
        }
    

    这可能是您所说的“在最初没有 UITextField 的情况下设置 inputAccessoryView”的意思

    • 另一种解决方法是通过仔细安排其动画让 textField “假装”为inputAccessoryView。但是此解决方案需要您的 textField 成为第一响应者。

    首先,您观察-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
      

      【讨论】:

      • 迄今为止关于 OP 问题的最简单实现。这与键盘的呈现和解除一起也非常好,并且是原生的动画。
      • @dezinezync 我很高兴知道它仍然有用,实际上它仍然可以顺利运行。感谢您的反馈!
      【解决方案3】:

      解决这个问题的一个hacky方法是在视图中有一个UITextField但隐藏,然后在它上面调用[textfield becomeFirstResponder]。

      我刚刚测试了它,这很有效

      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 版本基于刘耀东的回答。

        要求您在屏幕底部和文本视图之间设置垂直空间约束。请注意,设置偏移量必须发生在动画上下文之外,并且只有布局发生在动画上下文中。

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

        【讨论】:

        • 我仍然在这里解决这个问题,但看起来这是使用旧版本的 Swift 编写的。对于任何看到这个的人,这里有一篇关于 Swift 3 的 NotificationCenter addObserver stackoverflow.com/a/38615219/937682 的帖子
        猜你喜欢
        • 2011-08-22
        • 2021-08-14
        • 1970-01-01
        • 2015-10-06
        • 2013-03-25
        • 1970-01-01
        • 1970-01-01
        • 2012-09-21
        • 1970-01-01
        相关资源
        最近更新 更多