使用iOS SDK:

我有一个带UITextFields的UIView,可以启动键盘。我需要它能够:

启动键盘后,允许滚动UIScrollView的内容以查看其他文本字段自动“跳转”(通过向上滚动)或缩短

我知道我需要一个UIScrollView。我已经尝试将UIView的类更改为UIScrollView,但仍然无法上下滚动文本框。

我需要UIView和UIScrollView吗?一个在另一个里面吗?

要自动滚动到活动文本字段,需要执行哪些操作?

理想情况下,尽可能多的组件设置将在Interface Builder中完成。我只想编写需要的代码。

注意:我使用的UIView(或UIScrollView)是由一个选项卡(UITabBar)启动的,它需要正常工作。


我正在添加滚动条,只为键盘出现时使用。尽管不需要它,但我觉得它提供了一个更好的界面,例如,用户可以滚动和更改文本框。

当键盘上下移动时,我可以改变UIScrollView的框架大小。我只是在使用:

-(void)textFieldDidBeginEditing:(UITextField *)textField {
    //Keyboard becomes visible
    scrollView.frame = CGRectMake(scrollView.frame.origin.x,
                                  scrollView.frame.origin.y,
    scrollView.frame.size.width,
    scrollView.frame.size.height - 215 + 50);   // Resize
}

-(void)textFieldDidEndEditing:(UITextField *)textField {
    // Keyboard will hide
    scrollView.frame = CGRectMake(scrollView.frame.origin.x,
                                  scrollView.frame.origin.y,
                                  scrollView.frame.size.width,
                                  scrollView.frame.size.height + 215 - 50); // Resize
}

然而,这不会自动“向上移动”或将可见区域中的下部文本字段居中,这是我真正想要的。


当前回答

我们可以为Swift 4.1提供用户给定的代码

    let keyBoardSize = 80.0

    func keyboardWillShow() {

    if view.frame.origin.y >= 0 {
    viewMovedUp = true
     }
     else if view.frame.origin.y < 0 {
    viewMovedUp = false
   }
  }

func keyboardWillHide() {
 if view.frame.origin.y >= 0 {
    viewMovedUp = true
 }
 else if view.frame.origin.y < 0 {
    viewMovedUp = false
 }

}

func textFieldDidBeginEditing(_ textField: UITextField) {
   if sender.isEqual(mailTf) {
    //move the main view, so that the keyboard does not hide it.
    if view.frame.origin.y >= 0 {
        viewMovedUp = true
    }
  }
}

func setViewMovedUp(_ movedUp: Bool) {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.3)
    // if you want to slide up the view
let rect: CGRect = view.frame
if movedUp {

    rect.origin.y -= keyBoardSize
    rect.size.height += keyBoardSize
}
else {
    // revert back to the normal state.
    rect.origin.y += keyBoardSize
    rect.size.height -= keyBoardSize
 }
 view.frame = rect
 UIView.commitAnimations()
}

func viewWillAppear(_ animated: Bool)  {
super.viewWillAppear(animated)

NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
}

func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}

其他回答

我对UIScrollView由多个UITextField组成也有很多问题,其中一个或多个在编辑时会被键盘遮挡。

如果UIScrollView滚动不正确,请考虑以下几点。

1) 确保contentSize大于UIScrollView框架大小。理解UIScrollViews的方法是UIScrollView就像一个查看contentSize中定义的内容的窗口。因此,如果要让UIScrollview滚动到任何位置,contentSize必须大于UIScrollview。否则,不需要滚动,因为contentSize中定义的所有内容都已可见。BTW,默认contentSize=CGSizeZero。

2) 既然您已经了解到UIScrollView实际上是一个“内容”窗口,那么确保键盘不会遮挡UIScroll View的查看“窗口”的方法就是调整UIScrollView的大小,这样当键盘出现时,UIScrollView窗口的大小就等于UIScrollviewframe.size.height减去键盘的高度。这将确保您的窗口仅是那个小的可视区域。

3) 这里有一个陷阱:当我第一次实现这一点时,我想我必须获得编辑文本字段的CGRect,并调用UIScrollView的scrollRecToVisible方法。我通过调用scrollRecToVisible方法实现了UITextFieldDelegate方法textFieldDidBeginEditing。这实际上产生了一个奇怪的副作用,即滚动会将UITextField捕捉到位。在很长一段时间里,我都搞不清那是什么。然后我注释了textFieldDidBegginEditingDelegate方法,这一切都奏效了!!(???). 事实证明,我相信UIScrollView实际上隐式地将当前编辑的UITextField带入可视窗口。我对UITextFieldDelegate方法的实现以及随后对scrollRecToVisible的调用是多余的,这是产生奇怪副作用的原因。

因此,当键盘出现时,以下是在UIScrollView中正确滚动UITextField的步骤。

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad 
{
    [super viewDidLoad];

    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillShow:) 
                                                 name:UIKeyboardWillShowNotification 
                                               object:self.view.window];
    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillHide:) 
                                                 name:UIKeyboardWillHideNotification 
                                               object:self.view.window];
    keyboardIsShown = NO;
    //make contentSize bigger than your scrollSize (you will need to figure out for your own use case)
    CGSize scrollContentSize = CGSizeMake(320, 345);
    self.scrollView.contentSize = scrollContentSize;
}

- (void)keyboardWillHide:(NSNotification *)n
{
    NSDictionary* userInfo = [n userInfo];

    // get the size of the keyboard
    CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;


    // resize the scrollview
    CGRect viewFrame = self.scrollView.frame;
    // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
    viewFrame.size.height += (keyboardSize.height - kTabBarHeight);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.scrollView setFrame:viewFrame];
    [UIView commitAnimations];

    keyboardIsShown = NO;
}

- (void)keyboardWillShow:(NSNotification *)n
{
    // This is an ivar I'm using to ensure that we do not do the frame size adjustment on the `UIScrollView` if the keyboard is already shown.  This can happen if the user, after fixing editing a `UITextField`, scrolls the resized `UIScrollView` to another `UITextField` and attempts to edit the next `UITextField`.  If we were to resize the `UIScrollView` again, it would be disastrous.  NOTE: The keyboard notification will fire even when the keyboard is already shown.
    if (keyboardIsShown) {
        return;
    }

    NSDictionary* userInfo = [n userInfo];

    // get the size of the keyboard
    CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;

    // resize the noteView
    CGRect viewFrame = self.scrollView.frame;
    // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
    viewFrame.size.height -= (keyboardSize.height - kTabBarHeight);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.scrollView setFrame:viewFrame];
    [UIView commitAnimations];
    keyboardIsShown = YES;
}

在viewDidLoad上注册键盘通知在viewDidUnload中注销键盘nofitions确保contentSize设置为大于UIScrollView at viewDidLoad当有键盘时,缩小UIScrollView当键盘离开时,恢复UIScrollView。使用ivar来检测键盘是否已经显示在屏幕上,因为每次UITextField选项卡时都会发送键盘通知,即使键盘已经存在,以避免在UIScrollView已经缩小时缩小它

需要注意的一点是,当您单击另一个UITextField时,即使键盘已经在屏幕上,UIKeyboardWillShowNotification也会启动。当键盘已经在屏幕上时,我使用ivar来避免调整UIScrollView的大小。当键盘已经存在时,不小心调整UIScrollView的大小将是灾难性的!

希望这段代码能让你们中的一些人省去很多麻烦。

我迟到了一点。您应该在viewController上添加scrollView。

您必须实现以下2种方法。

TextField委托方法。

    - (void)textFieldDidBeginEditing:(UIView *)textField {
    [self scrollViewForTextField:reEnterPINTextField];
}

然后在委托方法中调用以下方法。

 - (void)scrollViewForTextField:(UIView *)textField {
    NSInteger keyboardHeight = KEYBOARD_HEIGHT;

    if ([textField UITextField.class]) {
        keyboardHeight += ((UITextField *)textField).keyboardControl.activeField.inputAccessoryView.frame.size.height;
    } 

    CGRect screenFrame = [UIScreen mainScreen].bounds;
    CGRect aRect = (CGRect){0, 0, screenFrame.size.width, screenFrame.size.height - ([UIApplication sharedApplication].statusBarHidden ? 0 : [UIApplication sharedApplication].statusBarFrame.size.height)};
    aRect.size.height -= keyboardHeight;
    CGPoint relativeOrigin = [UIView getOriginRelativeToScreenBounds:textField];
    CGPoint bottomPointOfTextField = CGPointMake(relativeOrigin.x, relativeOrigin.y + textField.frame.size.height);

    if (!CGRectContainsPoint(aRect, bottomPointOfTextField) ) {
        CGPoint scrollPoint = CGPointMake(0.0, bottomPointOfTextField.y -aRect.size.height);
        [contentSlidingView setContentOffset:scrollPoint animated:YES];
    }
}

如果文本字段应该位于屏幕底部,那么最神奇的解决方案是在视图控制器上覆盖以下内容:

override var inputAccessoryView: UIView? {
    return <yourTextField>
}

Swift 2.0版本:

添加UIScrollView并在其顶部添加textFields。将故事板引用到VC。

@IBOutlet weak var username: UITextField!
@IBOutlet weak var password: UITextField!
@IBOutlet weak var scrollView: UIScrollView!

添加以下方法:UITextFieldDelegate和UIScrollViewDelegate。

//MARK:- TEXTFIELD METHODS
    func textFieldShouldReturn(textField: UITextField) -> Bool {

        if(username.returnKeyType == UIReturnKeyType.Default) {
            password.becomeFirstResponder()
        }
        textField.resignFirstResponder()
        return true
    }
    func textFieldDidBeginEditing(textField: UITextField) {

        dispatch_async(dispatch_get_main_queue()) {

            let scrollPoint:CGPoint = CGPointMake(0,textField.frame.origin.y/4)
            self.scrollView!.setContentOffset(scrollPoint, animated: true);
        }
    }
    func textFieldShouldEndEditing(textField: UITextField) -> Bool {

        dispatch_async(dispatch_get_main_queue()) {
          UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) })
        }
        return true
    }
    override func touchesBegan(touches: Set<UITouch>,
        withEvent event: UIEvent?) {
            self.view.endEditing(true)
    }
    func scrollViewWillBeginDragging(scrollView: UIScrollView) {
        self.scrollView.scrollEnabled =  true

        dispatch_async(dispatch_get_main_queue()) {
            UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true)

            })
        }
    }

请在文本字段委派方法中添加这些行,以便在iPad中向上滚动。

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

    CGPoint pt;
    CGRect rc = [textField bounds];
    rc = [textField convertRect:rc toView:scrlView];
    pt = rc.origin;
    pt.x = 0;
    pt.y -= 100;

    [scrlView setContentOffset:pt animated:YES];

    scrlView.contentSize = CGSizeMake(scrlView.frame.size.width, button.frame.origin.y+button.frame.size.height + 8 + 370);
}