简体   繁体   English

仅当文本字段隐藏时才使用键盘移动视图

[英]Keyboard to move the view only if the textfield is hidden

I'm trying to get my app to move the view when the keyboard appears, and so far the results have been... mixed to say the least. 我正在尝试让我的应用在键盘出现时移动视图,到目前为止,结果至少可以说是混合的。 I can get it to move, thing is it's either hard coded or only works partially. 我可以移动它,它是经过硬编码或仅部分起作用的。

I have multiple Textfields in my view, when I tap on them, sometimes depending on where my scroll is it get's hidden by the keyboard. 当我点击它们时,我的视图中有多个文本字段,有时取决于滚动条在键盘上的隐藏位置。

Now what I need my app to do is to move the view to see the textfield only if the active textfield is hidden by the keyboard. 现在,我需要我的应用程序执行的操作是仅在活动文本字段被键盘隐藏时才移动视图以查看文本字段。

My Hierarchy for the view goes like this : 我的视图层次结构如下所示:

场景层次

So I have a Scroll view, and in the scroll View I have a UIView named ContentView, in the ContentView I have all my textfields and labels. 因此,我有一个Scroll视图,在滚动视图中有一个名为ContentView的UIView,在ContentView中,我有所有的文本字段和标签。

thing is, I can't hard code it since My app is universal, I need to have the keyboard move the view only if it hides the textfield. 事实是,由于我的应用程序是通用的,因此我无法对其进行硬编码,仅当键盘隐藏了文本字段时,才需要使键盘移动视图。 Because in a situation where the user is on an iPad, the View will likely never have to move 因为在用户使用iPad的情况下,视图可能永远不必移动

I used the following Stack overflow answers with no results : 我使用了以下堆栈溢出答案,但没有结果:

Swift: Scroll View only when a TextField or Button is hidden by the Keyboard Swift:仅当TextField或Button被键盘隐藏时才滚动查看

Move view with keyboard using Swift 使用Swift使用键盘移动视图

here's my code that actually comes from one of those answers : 这是我的代码,实际上来自这些答案之一:

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(NewPaxController.keyboardWillShow), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(NewPaxController.keyboardWillHide), name: UIKeyboardWillHideNotification, object: nil)

}



func keyboardWillShow(notification:NSNotification) {
    if keyboardIsPresent == false {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            self.ContentView.frame.origin.y -= keyboardSize.height
            keyboardIsPresent = true
        }
    }
}

func keyboardWillHide(notification:NSNotification) {
    if keyboardIsPresent == true {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            self.ContentView.frame.origin.y += keyboardSize.height
            keyboardIsPresent = false
        }
    }
}

I'm almost 100% sure all my error come from the fact the I have a ContentView... but I need it in my case. 我几乎100%确信我的所有错误均来自于我拥有ContentView ...的事实,但是我需要它。 Thanks in advance for your help 在此先感谢您的帮助

Here is the code for it, It is pretty straight forward, but if you still need help with it, I will explain it further. 这是它的代码,很简单,但是如果您仍然需要帮助,我将作进一步解释。

#pragma mark - Keyboard Observer events

-(void)keyboardWillShow:(NSNotification*)notification {

    NSDictionary *info = [notification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    keyboardHeight = kbSize.height;
    [self updateScrollViewPosition];
}

-(void)keyboardDidChange:(NSNotification *)notification {

    NSDictionary *info = [notification userInfo];
    CGSize kbSizeBegin = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGSize kbSizeEnd = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    if (kbSizeBegin.height != kbSizeEnd.height) {
        keyboardHeight = kbSizeEnd.height;
        if (activeTextField && [activeTextField isFirstResponder]) {
            [self updateScrollViewPosition];
        }
    }
}

-(void)keyboardWillHide:(NSNotification*)notification {

    keyboardHeight = 0;
    activeTextField = nil;
    [self resignAllTextFields];
}

#pragma mark - UITextFieldDelegate Methods

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    activeTextField = textField;
    return YES;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField {

    activeTextField = textField;
    [self updateScrollViewPosition];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {

    keyboardHeight = 0;
    activeTextField = nil;
    [textField resignFirstResponder];
    return YES;
}

#pragma mark - Update Method

-(void)updateScrollViewPosition {

    if (keyboardHeight > 0 && activeTextField) {
        CGRect frame = activeTextField.frame;
        CGFloat yPoint = scrollView.frame.origin.y+frame.origin.y+frame.size.height+8.0;
        CGFloat height = self.view.frame.size.height-keyboardHeight;
        CGFloat diff = yPoint-height;
        if (diff > 0.0) {
            [scrollView setContentOffset:CGPointMake(0, diff) animated:YES];
        }
        else {
            CGFloat diff = scrollView.contentSize.height-scrollView.contentOffset.y;
            if (diff<scrollView.frame.size.height) {
                diff = scrollView.contentSize.height-scrollView.frame.size.height;
                if (diff < 0) {
                    diff = 0.0;
                }
                [scrollView setContentOffset:CGPointMake(0, diff) animated:YES];
            }
        }
    }
    else {
        CGFloat diff = scrollView.contentSize.height-scrollView.contentOffset.y;
        if (diff<scrollView.frame.size.height) {
            diff = scrollView.contentSize.height-scrollView.frame.size.height;
            if (diff < 0) {
                diff = 0.0;
            }
            [scrollView setContentOffset:CGPointMake(0, diff) animated:YES];
        }
    }
}

#pragma mark

Edit: A simple resignAllTextFields method as requested. 编辑:根据要求的简单的resignAllTextFields方法。 containerView is the view which contains all the UITextField . containerView是包含所有UITextField的视图。

-(void)resignAllTextFields {

    for (UIView *view in containerView.subviews) {
        if ([view isKindOfClass:[UITextField class]]) {
            UITextField *textField = (UITextField*)view;
            [textField resignFirstResponder];
        }
    }
    [self updateScrollViewPosition];
}

You should not modify frames when keyboard shows up. 键盘出现时,您不应修改框架

Instead you need to set the bottom inset of the scrollview scrollView.contentInset.bottom from zero to keyboard height. 相反,您需要将scrollview scrollView.contentInset.bottom 的底部插图从零设置为键盘高度。 When the keyboard disappears, you set the inset back to zero. 当键盘消失时,您可以将插图设置回零。

This whole problem is solvable by mere 10 lines of code. 整个问题仅需10行代码即可解决。

literally get the keyboard height from notification, store it ion a local variable in the class while KB is showing, and use the value to set insets in delegate callback/event handler methods. 从通知中获取字面上的键盘高度,在显示KB时将其存储在类中的局部变量中,并使用该值在委托回调/事件处理程序方法中设置inset。

The trick here is that setting nonzero insets will effectively scroll the scrollview together with the content for you up by and that will push the current textfield up as well. 这里的技巧是,设置非零插入将有效地滚动滚动视图和内容,同时将当前文本字段向上推。

You should first try to locate the UITextField instance by using the following code. 您首先应该尝试使用以下代码查找UITextField实例。

extension UIView {

    func firstResponder() -> UIView? {
        if self.isFirstResponder() {
            return self
        }

        for subview in self.subviews {
            if subview.isFirstResponder() {
                return subview
            }
        }

        return nil
    }

}

In the keyboardWillShow: function decide if the textfield is visible or not if the keyboard comes up. keyboardWillShow:函数中确定文本字段是否可见(如果键盘抬起)。

func keyboardWillShow(notification:NSNotification) {
    if keyboardIsPresent == false {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue(),
            let inputView = self.ContentView.firstResponder()
            where inputView.frame.maxY > self.ContentView.frame.size.height - keyboardSize.height {

            self.ContentView.frame.origin.y -= keyboardSize.height
            keyboardIsPresent = true

        }
    }
}

Than only move the view back in the hide function if it was moved away. 如果仅将视图移开,则只能在隐藏功能中将其移回。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM